aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--com32/elflink/ldlinux/adv.c15
-rw-r--r--com32/elflink/ldlinux/advwrite.c9
-rw-r--r--com32/gfxboot/Makefile10
-rw-r--r--com32/include/bitsize/limits.h12
-rw-r--r--com32/include/bitsize/stddef.h14
-rw-r--r--com32/include/bitsize/stdint.h25
-rw-r--r--com32/include/bitsize/stdintconst.h18
-rw-r--r--com32/include/bitsize/stdintlimits.h22
-rw-r--r--com32/include/bitsize32/limits.h14
-rw-r--r--com32/include/bitsize32/stddef.h9
-rw-r--r--com32/include/bitsize32/stdint.h24
-rw-r--r--com32/include/bitsize32/stdintconst.h13
-rw-r--r--com32/include/bitsize32/stdintlimits.h23
-rw-r--r--com32/include/bitsize64/limits.h14
-rw-r--r--com32/include/bitsize64/stddef.h10
-rw-r--r--com32/include/bitsize64/stdint.h24
-rw-r--r--com32/include/bitsize64/stdintconst.h13
-rw-r--r--com32/include/bitsize64/stdintlimits.h23
-rw-r--r--com32/include/klibc/i386/archsetjmp.h19
-rw-r--r--com32/include/klibc/x86_64/archsetjmp.h21
-rw-r--r--com32/include/netinet/in.h8
-rw-r--r--com32/include/setjmp.h8
-rw-r--r--com32/include/sys/bitops.h30
-rw-r--r--com32/include/sys/cpu.h140
-rw-r--r--com32/include/sys/elfcommon.h50
-rw-r--r--com32/include/sys/i386/bitops.h54
-rw-r--r--com32/include/sys/i386/cpu.h135
-rw-r--r--com32/include/sys/i386/module.h35
-rw-r--r--com32/include/sys/module.h48
-rw-r--r--com32/include/sys/x86_64/bitops.h55
-rw-r--r--com32/include/sys/x86_64/cpu.h148
-rw-r--r--com32/include/sys/x86_64/module.h35
-rw-r--r--com32/include/syslinux/firmware.h54
-rw-r--r--com32/include/syslinux/linux.h99
-rw-r--r--com32/include/syslinux/memscan.h1
-rw-r--r--com32/include/syslinux/version.h6
-rw-r--r--com32/lib/Makefile146
-rw-r--r--com32/lib/i386/elf.ld184
-rw-r--r--com32/lib/i386/setjmp.S63
-rw-r--r--com32/lib/libgcc/__muldi3.S49
-rw-r--r--com32/lib/memcpy.S4
-rw-r--r--com32/lib/memcpy.c29
-rw-r--r--com32/lib/memmove.S4
-rw-r--r--com32/lib/memmove.c36
-rw-r--r--com32/lib/mempcpy.S4
-rw-r--r--com32/lib/mempcpy.c14
-rw-r--r--com32/lib/memset.S4
-rw-r--r--com32/lib/memset.c30
-rw-r--r--com32/lib/setjmp.S11
-rw-r--r--com32/lib/sys/ansi.c8
-rw-r--r--com32/lib/sys/ansicon_write.c93
-rw-r--r--com32/lib/sys/farcall.c10
-rw-r--r--com32/lib/sys/i386/x86_init_fpu.c58
-rw-r--r--com32/lib/sys/module/common.c81
-rw-r--r--com32/lib/sys/module/common.h11
-rw-r--r--com32/lib/sys/module/elfutils.h19
-rw-r--r--com32/lib/sys/module/i386/common.h65
-rw-r--r--com32/lib/sys/module/i386/elf_module.c599
-rw-r--r--com32/lib/sys/module/i386/shallow_module.c161
-rw-r--r--com32/lib/sys/module/x86_64/common.h64
-rw-r--r--com32/lib/sys/module/x86_64/elf_module.c631
-rw-r--r--com32/lib/sys/module/x86_64/elfutils.h64
-rw-r--r--com32/lib/sys/module/x86_64/shallow_module.c161
-rw-r--r--com32/lib/sys/vesa/efi/background.c456
-rw-r--r--com32/lib/sys/vesa/efi/cp865_8x16.h262
-rw-r--r--com32/lib/sys/vesa/efi/debug.h36
-rw-r--r--com32/lib/sys/vesa/efi/drawtxt.c317
-rw-r--r--com32/lib/sys/vesa/efi/fill.h63
-rw-r--r--com32/lib/sys/vesa/efi/fmtpixel.c101
-rw-r--r--com32/lib/sys/vesa/efi/i915resolution.c795
-rw-r--r--com32/lib/sys/vesa/efi/initvesa.c617
-rw-r--r--com32/lib/sys/vesa/efi/screencpy.c169
-rw-r--r--com32/lib/sys/vesa/efi/vesa.h129
-rw-r--r--com32/lib/sys/vesa/efi/video.h97
-rw-r--r--com32/lib/sys/vesacon_write.c4
-rw-r--r--com32/lib/sys/x86_64/x86_init_fpu.c58
-rw-r--r--com32/lib/sys/x86_init_fpu.c22
-rw-r--r--com32/lib/syslinux/cleanup.c2
-rw-r--r--com32/lib/syslinux/load_linux.c82
-rw-r--r--com32/lib/syslinux/memscan.c8
-rw-r--r--com32/lib/syslinux/serial.c15
-rw-r--r--com32/lib/syslinux/shuffle.c9
-rw-r--r--com32/lib/x86_64/elf.ld186
-rw-r--r--com32/lib/x86_64/setjmp.S54
-rw-r--r--com32/menu/Makefile6
-rw-r--r--com32/modules/ls.c2
-rw-r--r--com32/modules/zzjson.c6
-rw-r--r--com32/samples/advdump.c6
-rw-r--r--com32/samples/entrydump.c6
-rw-r--r--com32/samples/hello.c6
-rw-r--r--com32/samples/resolv.c6
-rw-r--r--com32/samples/serialinfo.c6
-rw-r--r--com32/sysdump/cpuid.c11
-rw-r--r--core/Makefile26
-rw-r--r--core/bios.c303
-rw-r--r--core/call16.c10
-rw-r--r--core/cleanup.c23
-rw-r--r--core/conio.c120
-rw-r--r--core/diskstart.inc2
-rw-r--r--core/elflink/load_env32.c21
-rw-r--r--core/extern.inc2
-rw-r--r--core/font.c13
-rw-r--r--core/fs/diskio.c390
-rw-r--r--core/fs/diskio_bios.c398
-rw-r--r--core/fs/fs.c15
-rw-r--r--core/graphics.c2
-rw-r--r--core/i386/syslinux.ld428
-rw-r--r--core/include/bios.h6
-rw-r--r--core/include/core.h9
-rw-r--r--core/include/disk.h18
-rw-r--r--core/include/fs.h1
-rw-r--r--core/init.c80
-rw-r--r--core/init.inc4
-rw-r--r--core/isolinux.asm2
-rw-r--r--core/lzo/enter.ash11
-rw-r--r--core/lzo/leave.ash11
-rw-r--r--core/lzo/lzo_asm.h4
-rw-r--r--core/mem/free.c4
-rw-r--r--core/mem/init.c2
-rw-r--r--core/mem/malloc.c11
-rw-r--r--core/pxelinux.asm4
-rw-r--r--core/syslinux.ld1
-rw-r--r--core/timer.inc4
-rw-r--r--core/x86_64/syslinux.ld428
-rw-r--r--diag/mbr/Makefile2
-rw-r--r--dos/stdlib.h7
-rw-r--r--efi/Makefile67
-rw-r--r--efi/adv.c362
-rw-r--r--efi/adv.h29
-rw-r--r--efi/console.c175
-rw-r--r--efi/diskio.c91
-rw-r--r--efi/efi.h13
-rw-r--r--efi/fio.c283
-rw-r--r--efi/fio.h43
-rw-r--r--efi/i386/syslinux.ld176
-rw-r--r--efi/main.c786
-rw-r--r--efi/syslinux.ld176
-rw-r--r--efi/wrapper.c246
-rw-r--r--efi/wrapper.h164
-rw-r--r--efi/x86_64/syslinux.ld176
-rw-r--r--gpxe/Makefile4
-rw-r--r--mbr/Makefile5
-rw-r--r--mbr/i386/mbr.ld73
-rw-r--r--mbr/x86_64/mbr.ld72
-rw-r--r--memdisk/Makefile3
-rw-r--r--memdisk/i386/memdisk.ld140
-rw-r--r--memdisk/memcpy.c29
-rw-r--r--memdisk/memdisk.h3
-rw-r--r--memdisk/memmove.c36
-rw-r--r--memdisk/memset.c30
-rw-r--r--memdisk/setup.c6
-rw-r--r--memdisk/start32.S6
-rw-r--r--memdisk/x86_64/memdisk.ld140
-rw-r--r--memdump/code16.h2
-rw-r--r--mk/com32.mk38
-rw-r--r--mk/efi.mk60
-rw-r--r--mk/elf.mk31
-rw-r--r--mk/embedded.mk27
-rw-r--r--mk/lib.mk181
-rw-r--r--mk/syslinux.mk6
161 files changed, 12211 insertions, 1228 deletions
diff --git a/Makefile b/Makefile
index 499ca5e3..e0294280 100644
--- a/Makefile
+++ b/Makefile
@@ -31,12 +31,23 @@ include $(MAKEDIR)/syslinux.mk
#
# List of module objects that should be installed for all derivatives
+ifndef EFI_BUILD
MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \
com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
com32/elflink/ldlinux/*.c32
+else
+# memdump is BIOS specific code exclude it for EFI
+# FIXME: Prune other BIOS-centric modules
+MODULES = memdisk/memdisk modules/*.com \
+ com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
+ com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
+ com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
+ com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
+ com32/elflink/ldlinux/*.c32
+endif
# syslinux.exe is BTARGET so as to not require everyone to have the
# mingw suite installed
@@ -55,8 +66,15 @@ BOBJECTS = $(BTARGET) \
# Note: libinstaller is both a BSUBDIR and an ISUBDIR. It contains
# files that depend only on the B phase, but may have to be regenerated
# for "make installer".
+ifndef EFI_BUILD
BSUBDIRS = codepage com32 lzo core memdisk modules mbr memdump gpxe sample \
- diag libinstaller dos win32 win64 dosutil
+ diag libinstaller dos win32 win64 dosutil efi
+else
+# memdump is BIOS specific code exclude it for EFI
+# FIXME: Prune other BIOS-centric modules
+BSUBDIRS = codepage com32 lzo core memdisk modules mbr gpxe sample \
+ diag libinstaller win32 win64 dosutil efi
+endif
ITARGET =
IOBJECTS = $(ITARGET) \
utils/gethostip utils/isohybrid utils/mkdiskimage \
diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c
index b81361f2..ae473908 100644
--- a/com32/elflink/ldlinux/adv.c
+++ b/com32/elflink/ldlinux/adv.c
@@ -32,24 +32,13 @@
*/
#include <syslinux/adv.h>
+#include <syslinux/firmware.h>
#include <klibc/compiler.h>
-#include <inttypes.h>
-#include <com32.h>
void *__syslinux_adv_ptr;
size_t __syslinux_adv_size;
-extern void adv_init(void);
void __constructor __syslinux_init(void)
{
- static com32sys_t reg;
-
- /* Initialize the ADV structure */
- reg.eax.w[0] = 0x0025;
- __intcall(0x22, &reg, NULL);
-
- reg.eax.w[0] = 0x001c;
- __intcall(0x22, &reg, &reg);
- __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
- __syslinux_adv_size = reg.ecx.w[0];
+ firmware->adv_ops->init();
}
diff --git a/com32/elflink/ldlinux/advwrite.c b/com32/elflink/ldlinux/advwrite.c
index 4152eea5..95a311a8 100644
--- a/com32/elflink/ldlinux/advwrite.c
+++ b/com32/elflink/ldlinux/advwrite.c
@@ -32,14 +32,9 @@
*/
#include <syslinux/adv.h>
-#include <klibc/compiler.h>
-#include <com32.h>
+#include <syslinux/firmware.h>
int syslinux_adv_write(void)
{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x001d;
- __intcall(0x22, &reg, &reg);
- return (reg.eflags.l & EFLAGS_CF) ? -1 : 0;
+ return firmware->adv_ops->write();
}
diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile
index f2a73762..a2420c42 100644
--- a/com32/gfxboot/Makefile
+++ b/com32/gfxboot/Makefile
@@ -23,12 +23,22 @@ gfxboot.c32 : gfxboot.o realmode_callback.o $(LIBS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
realmode_callback.o: realmode_callback.asm
+ifeq ($(ARCH),i386)
$(NASM) -f bin -O99 -o $*.tmp -l $*.lst $<
$(OBJCOPY) -B i386 -I binary -O elf32-i386 \
--redefine-sym _binary_$*_tmp_start=$*_start \
--redefine-sym _binary_$*_tmp_end=$*_end \
--strip-symbol _binary_$*_tmp_size \
$*.tmp $@
+endif
+ifeq ($(ARCH),x86_64)
+ $(NASM) -f bin -O99 -o $*.tmp -l $*.lst $<
+ $(OBJCOPY) -B i386:x86-64 -I binary -O elf64-x86-64 \
+ --redefine-sym _binary_$*_tmp_start=$*_start \
+ --redefine-sym _binary_$*_tmp_end=$*_end \
+ --strip-symbol _binary_$*_tmp_size \
+ $*.tmp $@
+endif
tidy dist:
rm -f *.o *.lo *.a *.lst .*.d *.tmp
diff --git a/com32/include/bitsize/limits.h b/com32/include/bitsize/limits.h
index f90e524b..7129c4a6 100644
--- a/com32/include/bitsize/limits.h
+++ b/com32/include/bitsize/limits.h
@@ -5,10 +5,12 @@
#ifndef _BITSIZE_LIMITS_H
#define _BITSIZE_LIMITS_H
-#define LONG_BIT 32
-
-#define LONG_MIN (-2147483647L-1)
-#define LONG_MAX 2147483647L
-#define ULONG_MAX 4294967295UL
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/limits.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/limits.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
#endif /* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize/stddef.h b/com32/include/bitsize/stddef.h
index 213e8ab7..04418a04 100644
--- a/com32/include/bitsize/stddef.h
+++ b/com32/include/bitsize/stddef.h
@@ -1,14 +1,16 @@
/*
- * bits32/stddef.h
+ * Include stddef.h as appropriate for architecture
*/
#ifndef _BITSIZE_STDDEF_H
#define _BITSIZE_STDDEF_H
-#define _SIZE_T
-typedef unsigned int size_t;
-
-#define _PTRDIFF_T
-typedef signed long ptrdiff_t;
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stddef.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stddef.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
#endif /* _BITSIZE_STDDEF_H */
diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h
index 8e444b6d..7e7b2355 100644
--- a/com32/include/bitsize/stdint.h
+++ b/com32/include/bitsize/stdint.h
@@ -8,27 +8,16 @@
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
-typedef long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
-typedef unsigned long long int uint64_t;
-
-typedef int int_fast16_t;
-typedef int int_fast32_t;
-
-typedef unsigned int uint_fast16_t;
-typedef unsigned int uint_fast32_t;
-
-typedef int intptr_t;
-typedef unsigned int uintptr_t;
-
-#define __INT64_C(c) c ## LL
-#define __UINT64_C(c) c ## ULL
-
-#define __PRI64_RANK "ll"
-#define __PRIFAST_RANK ""
-#define __PRIPTR_RANK ""
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stdint.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stdint.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
#endif /* _BITSIZE_STDINT_H */
diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h
index 7db63bdf..b2f3141a 100644
--- a/com32/include/bitsize/stdintconst.h
+++ b/com32/include/bitsize/stdintconst.h
@@ -1,18 +1,16 @@
/*
- * bits32/stdintconst.h
+ * bitsize/stdintconst.h
*/
#ifndef _BITSIZE_STDINTCONST_H
#define _BITSIZE_STDINTCONST_H
-#define INT_FAST16_C(c) INT32_C(c)
-#define INT_FAST32_C(c) INT32_C(c)
-
-#define UINT_FAST16_C(c) UINT32_C(c)
-#define UINT_FAST32_C(c) UINT32_C(c)
-
-#define INTPTR_C(c) INT32_C(c)
-#define UINTPTR_C(c) UINT32_C(c)
-#define PTRDIFF_C(c) INT32_C(c)
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stdintconst.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stdintconst.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h
index d85094d9..c342c448 100644
--- a/com32/include/bitsize/stdintlimits.h
+++ b/com32/include/bitsize/stdintlimits.h
@@ -1,22 +1,16 @@
/*
- * bits32/stdintlimits.h
+ * bitsize/stdintlimits.h
*/
#ifndef _BITSIZE_STDINTLIMITS_H
#define _BITSIZE_STDINTLIMITS_H
-#define INT_FAST16_MIN INT32_MIN
-#define INT_FAST32_MIN INT32_MIN
-#define INT_FAST16_MAX INT32_MAX
-#define INT_FAST32_MAX INT32_MAX
-#define UINT_FAST16_MAX UINT32_MAX
-#define UINT_FAST32_MAX UINT32_MAX
-
-#define INTPTR_MIN INT32_MIN
-#define INTPTR_MAX INT32_MAX
-#define UINTPTR_MAX UINT32_MAX
-
-#define PTRDIFF_MIN INT32_MIN
-#define PTRDIFF_MAX INT32_MAX
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stdintlimits.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stdintlimits.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/com32/include/bitsize32/limits.h b/com32/include/bitsize32/limits.h
new file mode 100644
index 00000000..f19205fe
--- /dev/null
+++ b/com32/include/bitsize32/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits32/limits.h
+ */
+
+#ifndef _BITSIZE32_LIMITS_H
+#define _BITSIZE32_LIMITS_H
+
+#define LONG_BIT 32
+
+#define LONG_MIN (-2147483647L-1)
+#define LONG_MAX 2147483647L
+#define ULONG_MAX 4294967295UL
+
+#endif /* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize32/stddef.h b/com32/include/bitsize32/stddef.h
new file mode 100644
index 00000000..c34c675c
--- /dev/null
+++ b/com32/include/bitsize32/stddef.h
@@ -0,0 +1,9 @@
+/*
+ * bits32/stddef.h
+ */
+
+#define _SIZE_T
+typedef unsigned int size_t;
+
+#define _PTRDIFF_T
+typedef signed long ptrdiff_t;
diff --git a/com32/include/bitsize32/stdint.h b/com32/include/bitsize32/stdint.h
new file mode 100644
index 00000000..bdc69705
--- /dev/null
+++ b/com32/include/bitsize32/stdint.h
@@ -0,0 +1,24 @@
+/*
+ * bits32/stdint.h
+ */
+
+
+typedef long long int int64_t;
+
+typedef unsigned long long int uint64_t;
+
+typedef int int_fast16_t;
+typedef int int_fast32_t;
+
+typedef unsigned int uint_fast16_t;
+typedef unsigned int uint_fast32_t;
+
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+#define __INT64_C(c) c ## LL
+#define __UINT64_C(c) c ## ULL
+
+#define __PRI64_RANK "ll"
+#define __PRIFAST_RANK ""
+#define __PRIPTR_RANK ""
diff --git a/com32/include/bitsize32/stdintconst.h b/com32/include/bitsize32/stdintconst.h
new file mode 100644
index 00000000..71ece423
--- /dev/null
+++ b/com32/include/bitsize32/stdintconst.h
@@ -0,0 +1,13 @@
+/*
+ * bits32/stdintconst.h
+ */
+
+#define INT_FAST16_C(c) INT32_C(c)
+#define INT_FAST32_C(c) INT32_C(c)
+
+#define UINT_FAST16_C(c) UINT32_C(c)
+#define UINT_FAST32_C(c) UINT32_C(c)
+
+#define INTPTR_C(c) INT32_C(c)
+#define UINTPTR_C(c) UINT32_C(c)
+#define PTRDIFF_C(c) INT32_C(c)
diff --git a/com32/include/bitsize32/stdintlimits.h b/com32/include/bitsize32/stdintlimits.h
new file mode 100644
index 00000000..175cdcd4
--- /dev/null
+++ b/com32/include/bitsize32/stdintlimits.h
@@ -0,0 +1,23 @@
+/*
+ * bits32/stdintlimits.h
+ */
+
+#define INT_FAST16_MIN INT32_MIN
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST16_MAX INT32_MAX
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+
+/* sig_atomic_t limit */
+# define SIG_ATOMIC_MIN INT32_MIN //(-2147483647-1)
+# define SIG_ATOMIC_MAX INT32_MAX //(2147483647)
+/* size_t limit */
+# define SIZE_MAX UINT32_MAX //(4294967295U)
diff --git a/com32/include/bitsize64/limits.h b/com32/include/bitsize64/limits.h
new file mode 100644
index 00000000..1acb1bc8
--- /dev/null
+++ b/com32/include/bitsize64/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits64/limits.h
+ */
+
+#ifndef _BITSIZE64_LIMITS_H
+#define _BITSIZE64_LIMITS_H
+
+#define LONG_BIT 64
+
+#define LONG_MIN (-9223372036854775807L-1)
+#define LONG_MAX 9223372036854775807L
+#define ULONG_MAX 18446744073709551615UL
+
+#endif /* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize64/stddef.h b/com32/include/bitsize64/stddef.h
new file mode 100644
index 00000000..c61bf8ce
--- /dev/null
+++ b/com32/include/bitsize64/stddef.h
@@ -0,0 +1,10 @@
+/*
+ * bits64/stddef.h
+ */
+
+#define _SIZE_T
+typedef unsigned long size_t;
+
+#define _PTRDIFF_T
+typedef signed long ptrdiff_t;
+
diff --git a/com32/include/bitsize64/stdint.h b/com32/include/bitsize64/stdint.h
new file mode 100644
index 00000000..91930003
--- /dev/null
+++ b/com32/include/bitsize64/stdint.h
@@ -0,0 +1,24 @@
+/*
+ * bits64/stdint.h
+ */
+
+
+typedef long int int64_t;
+
+typedef unsigned long int uint64_t;
+
+typedef long int int_fast16_t;
+typedef long int int_fast32_t;
+
+typedef unsigned long int uint_fast16_t;
+typedef unsigned long int uint_fast32_t;
+
+typedef long int intptr_t;
+typedef unsigned long int uintptr_t;
+
+#define __INT64_C(c) c ## L
+#define __UINT64_C(c) c ## UL
+
+#define __PRI64_RANK "l"
+#define __PRIFAST_RANK "l"
+#define __PRIPTR_RANK "l"
diff --git a/com32/include/bitsize64/stdintconst.h b/com32/include/bitsize64/stdintconst.h
new file mode 100644
index 00000000..139ab203
--- /dev/null
+++ b/com32/include/bitsize64/stdintconst.h
@@ -0,0 +1,13 @@
+/*
+ * bits64/stdintconst.h
+ */
+
+#define INT_FAST16_C(c) INT64_C(c)
+#define INT_FAST32_C(c) INT64_C(c)
+
+#define UINT_FAST16_C(c) UINT64_C(c)
+#define UINT_FAST32_C(c) UINT64_C(c)
+
+#define INTPTR_C(c) INT64_C(c)
+#define UINTPTR_C(c) UINT64_C(c)
+#define PTRDIFF_C(c) INT64_C(c)
diff --git a/com32/include/bitsize64/stdintlimits.h b/com32/include/bitsize64/stdintlimits.h
new file mode 100644
index 00000000..a775a7fd
--- /dev/null
+++ b/com32/include/bitsize64/stdintlimits.h
@@ -0,0 +1,23 @@
+/*
+ * bits64/stdintlimits.h
+ */
+
+#define INT_FAST16_MIN INT64_MIN
+#define INT_FAST32_MIN INT64_MIN
+#define INT_FAST16_MAX INT64_MAX
+#define INT_FAST32_MAX INT64_MAX
+#define UINT_FAST16_MAX UINT64_MAX
+#define UINT_FAST32_MAX UINT64_MAX
+
+#define INTPTR_MIN INT64_MIN
+#define INTPTR_MAX INT64_MAX
+#define UINTPTR_MAX UINT64_MAX
+
+#define PTRDIFF_MIN INT64_MIN
+#define PTRDIFF_MAX INT64_MAX
+
+/* sig_atomic_t limit */
+# define SIG_ATOMIC_MAX INT32_MAX //(2147483647)
+# define SIG_ATOMIC_MIN (-SIG_ATOMIC_MAX-1) //(-2147483647-1)
+/* size_t limit */
+# define SIZE_MAX UINT64_MAX
diff --git a/com32/include/klibc/i386/archsetjmp.h b/com32/include/klibc/i386/archsetjmp.h
new file mode 100644
index 00000000..a0def6a1
--- /dev/null
+++ b/com32/include/klibc/i386/archsetjmp.h
@@ -0,0 +1,19 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned int __ebx;
+ unsigned int __esp;
+ unsigned int __ebp;
+ unsigned int __esi;
+ unsigned int __edi;
+ unsigned int __eip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/com32/include/klibc/x86_64/archsetjmp.h b/com32/include/klibc/x86_64/archsetjmp.h
new file mode 100644
index 00000000..454fc60a
--- /dev/null
+++ b/com32/include/klibc/x86_64/archsetjmp.h
@@ -0,0 +1,21 @@
+/*
+ * arch/x86_64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __rbx;
+ unsigned long __rsp;
+ unsigned long __rbp;
+ unsigned long __r12;
+ unsigned long __r13;
+ unsigned long __r14;
+ unsigned long __r15;
+ unsigned long __rip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h
index d2af351f..d3fba17f 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -27,8 +27,16 @@ static inline __constfunc uint16_t __htons(uint16_t v)
static inline __constfunc uint32_t __htonl(uint32_t v)
{
+#if __SIZEOF_POINTER__ == 4
asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
: "+q" (v));
+#elif __SIZEOF_POINTER__ == 8
+ asm("bswap %0"
+ : "=r" (v)
+ : "0" (v));
+#else
+#error "unable to build for architecture"
+#endif
return v;
}
diff --git a/com32/include/setjmp.h b/com32/include/setjmp.h
index 11b18fbd..e7090955 100644
--- a/com32/include/setjmp.h
+++ b/com32/include/setjmp.h
@@ -9,7 +9,13 @@
#include <klibc/compiler.h>
#include <stddef.h>
-#include <klibc/archsetjmp.h>
+#if __SIZEOF_POINTER__ == 4
+#include <klibc/i386/archsetjmp.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <klibc/x86_64/archsetjmp.h>
+#else
+#error "unsupported architecture"
+#endif
__extern int setjmp(jmp_buf);
__extern __noreturn longjmp(jmp_buf, int);
diff --git a/com32/include/sys/bitops.h b/com32/include/sys/bitops.h
index 40e09fe7..de30d932 100644
--- a/com32/include/sys/bitops.h
+++ b/com32/include/sys/bitops.h
@@ -36,27 +36,11 @@
#include <klibc/compiler.h>
-static inline void set_bit(long __bit, void *__bitmap)
-{
- asm volatile("btsl %1,%0"
- : "+m" (*(unsigned char *)__bitmap)
- : "Ir" (__bit) : "memory");
-}
-
-static inline void clr_bit(long __bit, void *__bitmap)
-{
- asm volatile("btcl %1,%0"
- : "+m" (*(unsigned char *)__bitmap)
- : "Ir" (__bit) : "memory");
-}
-
-static inline int __purefunc test_bit(long __bit, const void *__bitmap)
-{
- unsigned char __r;
- asm("btl %2,%1; setc %0"
- : "=qm" (__r)
- : "m" (*(const unsigned char *)__bitmap), "Ir" (__bit));
- return __r;
-}
-
+#if __SIZEOF_POINTER__ == 4
+#include <i386/bitops.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/bitops.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
#endif /* _BITOPS_H */
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index 53a6250e..05c98843 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -5,138 +5,12 @@
#include <stdint.h>
#include <klibc/compiler.h>
-static inline uint64_t rdtsc(void)
-{
- uint64_t v;
- asm volatile("rdtsc" : "=A" (v));
- return v;
-}
-
-static inline uint32_t rdtscl(void)
-{
- uint32_t v;
- asm volatile("rdtsc" : "=a" (v) : : "edx");
- return v;
-}
-
-static inline void cpuid_count(uint32_t op, uint32_t cnt,
- uint32_t * eax, uint32_t * ebx,
- uint32_t * ecx, uint32_t * edx)
-{
- asm volatile("movl %%ebx,%1 ; "
- "cpuid ; "
- "xchgl %1,%%ebx"
- : "=a" (*eax), "=SD" (*ebx), "=c" (*ecx), "=d" (*edx)
- : "a"(op), "c"(cnt));
-}
-
-static inline void cpuid(uint32_t op, uint32_t * eax, uint32_t * ebx,
- uint32_t * ecx, uint32_t * edx)
-{
- cpuid_count(op, 0, eax, ebx, ecx, edx);
-}
-
-static inline __constfunc uint32_t cpuid_eax(uint32_t level)
-{
- uint32_t v;
-
- asm volatile("pushl %%ebx ; "
- "cpuid ; "
- "popl %%ebx"
- : "=a" (v)
- : "a"(level)
- : "ecx", "edx");
- return v;
-}
-
-static inline __constfunc uint32_t cpuid_ebx(uint32_t level)
-{
- uint32_t v;
-
- asm volatile("movl %%ebx,%0 ; "
- "cpuid ; "
- "xchgl %0,%%ebx"
- : "=SD" (v), "+a" (level)
- : : "ecx", "edx");
- return v;
-}
-
-static inline __constfunc uint32_t cpuid_ecx(uint32_t level)
-{
- uint32_t v;
-
- asm volatile("pushl %%ebx ; "
- "cpuid ; "
- "popl %%ebx"
- : "=c" (v), "+a" (level)
- : : "edx");
- return v;
-}
-
-static inline __constfunc uint32_t cpuid_edx(uint32_t level)
-{
- uint32_t v;
-
- asm volatile("pushl %%ebx ; "
- "cpuid ; "
- "popl %%ebx"
- : "=d" (v), "+a" (level)
- : : "ecx");
- return v;
-}
-
-/* Standard macro to see if a specific flag is changeable */
-static inline __constfunc bool cpu_has_eflag(uint32_t flag)
-{
- uint32_t f0, f1;
-
- asm("pushfl ; "
- "pushfl ; "
- "popl %0 ; "
- "movl %0,%1 ; "
- "xorl %2,%1 ; "
- "pushl %1 ; "
- "popfl ; "
- "pushfl ; "
- "popl %1 ; "
- "popfl"
- : "=&r" (f0), "=&r" (f1)
- : "ri" (flag));
-
- return !!((f0^f1) & flag);
-}
-
-static inline uint64_t rdmsr(uint32_t msr)
-{
- uint64_t v;
-
- asm volatile("rdmsr" : "=A" (v) : "c"(msr));
- return v;
-}
-
-static inline void wrmsr(uint64_t v, uint32_t msr)
-{
- asm volatile("wrmsr" : : "A" (v), "c" (msr));
-}
-
-static inline void cpu_relax(void)
-{
- asm volatile("rep ; nop");
-}
-
-static inline void hlt(void)
-{
- asm volatile("hlt");
-}
-
-static inline void cli(void)
-{
- asm volatile("cli");
-}
-
-static inline void sti(void)
-{
- asm volatile("sti");
-}
+#if __SIZEOF_POINTER__ == 4
+#include <i386/cpu.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/cpu.h>
+#else
+#error "unsupported architecture"
+#endif
#endif
diff --git a/com32/include/sys/elfcommon.h b/com32/include/sys/elfcommon.h
index 8d6ddb05..99b5ad10 100644
--- a/com32/include/sys/elfcommon.h
+++ b/com32/include/sys/elfcommon.h
@@ -361,4 +361,54 @@
/* Keep this the last entry. */
#define R_386_NUM 38
+/* AMD x86-64 relocations. */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
+ offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
+ to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
+ to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
+ to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
+#define R_X86_64_PC64 24 /* PC relative 64 bit */
+#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
+ offset to GOT */
+#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
+ to GOT entry */
+#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
+ to PLT entry */
+#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
+#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
+ descriptor. */
+#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
+
+#define R_X86_64_NUM 38
+
#endif /* _SYS_ELFCOMMON_H */
diff --git a/com32/include/sys/i386/bitops.h b/com32/include/sys/i386/bitops.h
new file mode 100644
index 00000000..663b267a
--- /dev/null
+++ b/com32/include/sys/i386/bitops.h
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * i386 bitops.h
+ *
+ * Simple bitwise operations
+ */
+static inline void set_bit(long __bit, void *__bitmap)
+{
+ asm volatile("btsl %1,%0"
+ : "+m" (*(unsigned char *)__bitmap)
+ : "Ir" (__bit) : "memory");
+}
+
+static inline void clr_bit(long __bit, void *__bitmap)
+{
+ asm volatile("btcl %1,%0"
+ : "+m" (*(unsigned char *)__bitmap)
+ : "Ir" (__bit) : "memory");
+}
+
+static inline int __purefunc test_bit(long __bit, const void *__bitmap)
+{
+ unsigned char __r;
+ asm("btl %2,%1; setc %0"
+ : "=qm" (__r)
+ : "m" (*(const unsigned char *)__bitmap), "Ir" (__bit));
+ return __r;
+}
diff --git a/com32/include/sys/i386/cpu.h b/com32/include/sys/i386/cpu.h
new file mode 100644
index 00000000..63d0f5ed
--- /dev/null
+++ b/com32/include/sys/i386/cpu.h
@@ -0,0 +1,135 @@
+/* i386 cpu.h */
+
+static inline uint64_t rdtsc(void)
+{
+ uint64_t v;
+ asm volatile("rdtsc" : "=A" (v));
+ return v;
+}
+
+static inline uint32_t rdtscl(void)
+{
+ uint32_t v;
+ asm volatile("rdtsc" : "=a" (v) : : "edx");
+ return v;
+}
+
+static inline void cpuid_count(uint32_t op, uint32_t cnt,
+ uint32_t * eax, uint32_t * ebx,
+ uint32_t * ecx, uint32_t * edx)
+{
+ asm volatile("movl %%ebx,%1 ; "
+ "cpuid ; "
+ "xchgl %1,%%ebx"
+ : "=a" (*eax), "=SD" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "a"(op), "c"(cnt));
+}
+
+static inline void cpuid(uint32_t op, uint32_t * eax, uint32_t * ebx,
+ uint32_t * ecx, uint32_t * edx)
+{
+ cpuid_count(op, 0, eax, ebx, ecx, edx);
+}
+
+static inline __constfunc uint32_t cpuid_eax(uint32_t level)
+{
+ uint32_t v;
+
+ asm volatile("pushl %%ebx ; "
+ "cpuid ; "
+ "popl %%ebx"
+ : "=a" (v)
+ : "a"(level)
+ : "ecx", "edx");
+ return v;
+}
+
+static inline __constfunc uint32_t cpuid_ebx(uint32_t level)
+{
+ uint32_t v;
+
+ asm volatile("movl %%ebx,%0 ; "
+ "cpuid ; "
+ "xchgl %0,%%ebx"
+ : "=SD" (v), "+a" (level)
+ : : "ecx", "edx");
+ return v;
+}
+
+static inline __constfunc uint32_t cpuid_ecx(uint32_t level)
+{
+ uint32_t v;
+
+ asm volatile("pushl %%ebx ; "
+ "cpuid ; "
+ "popl %%ebx"
+ : "=c" (v), "+a" (level)
+ : : "edx");
+ return v;
+}
+
+static inline __constfunc uint32_t cpuid_edx(uint32_t level)
+{
+ uint32_t v;
+
+ asm volatile("pushl %%ebx ; "
+ "cpuid ; "
+ "popl %%ebx"
+ : "=d" (v), "+a" (level)
+ : : "ecx");
+ return v;
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline __constfunc bool cpu_has_eflag(uint32_t flag)
+{
+ uint32_t f0, f1;
+
+ asm("pushfl ; "
+ "pushfl ; "
+ "popl %0 ; "
+ "movl %0,%1 ; "
+ "xorl %2,%1 ; "
+ "pushl %1 ; "
+ "popfl ; "
+ "pushfl ; "
+ "popl %1 ; "
+ "popfl"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (flag));
+
+ return !!((f0^f1) & flag);
+}
+
+static inline uint64_t rdmsr(uint32_t msr)
+{
+ uint64_t v;
+
+ asm volatile("rdmsr" : "=A" (v) : "c"(msr));
+ return v;
+}
+
+static inline void wrmsr(uint64_t v, uint32_t msr)
+{
+ asm volatile("wrmsr" : : "A" (v), "c" (msr));
+}
+
+static inline void cpu_relax(void)
+{
+ asm volatile("rep ; nop");
+}
+
+static inline void hlt(void)
+{
+ asm volatile("hlt");
+}
+
+static inline void cli(void)
+{
+ asm volatile("cli");
+}
+
+static inline void sti(void)
+{
+ asm volatile("sti");
+}
diff --git a/com32/include/sys/i386/module.h b/com32/include/sys/i386/module.h
new file mode 100644
index 00000000..21988ead
--- /dev/null
+++ b/com32/include/sys/i386/module.h
@@ -0,0 +1,35 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF modules definitions and services.
+ */
+
+#ifndef I386_MODULE_H_
+#define I386_MODULE_H_
+
+#include <elf.h>
+
+/*
+ * Accepted values for various ELF header parameters found in an ELF dynamic
+ * object.
+ */
+#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules
+#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value
+#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
+#define MODULE_ELF_VERSION EV_CURRENT // Object version
+#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
+#define MODULE_ELF_MACHINE EM_386 // Target architecture
+
+#define ELF_MOD_SYS "32 bit"
+
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Dyn Elf_Dyn;
+typedef Elf32_Word Elf_Word;
+typedef Elf32_Off Elf_Off;
+typedef Elf32_Sym Elf_Sym;
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Rel Elf_Rel;
+typedef Elf32_Word Elf_Bword;
+
+#endif // I386_MODULE_H_
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index eabc9e0f..88c8f8ec 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -4,7 +4,6 @@
* Dynamic ELF modules definitions and services.
*/
-
#ifndef MODULE_H_
#define MODULE_H_
@@ -15,6 +14,14 @@
#include <stdbool.h>
#include <linux/list.h>
+#if __SIZEOF_POINTER__ == 4
+#include <i386/module.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/module.h>
+#else
+#error "unsupported architecture"
+#endif
+
/*
* The maximum length of the module file name (including path), stored
* in the struct module descriptor.
@@ -91,26 +98,26 @@ struct elf_module {
module_main_t main_func; // The main function (for executable modules)
void *module_addr; // The module location in the memory
- Elf32_Addr base_addr; // The base address of the module
- Elf32_Word module_size; // The module size in memory
+ Elf_Addr base_addr; // The base address of the module
+ Elf_Word module_size; // The module size in memory
- Elf32_Word *hash_table; // The symbol hash table
- Elf32_Word *ghash_table; // The GNU style hash table
+ Elf_Word *hash_table; // The symbol hash table
+ Elf_Word *ghash_table; // The GNU style hash table
char *str_table; // The string table
void *sym_table; // The symbol table
void *got; // The Global Offset Table
- Elf32_Dyn *dyn_table; // Dynamic loading information table
+ Elf_Dyn *dyn_table; // Dynamic loading information table
- Elf32_Word strtable_size; // The size of the string table
- Elf32_Word syment_size; // The size of a symbol entry
- Elf32_Word symtable_size; // The size of the symbol table
+ Elf_Word strtable_size; // The size of the string table
+ Elf_Word syment_size; // The size of a symbol entry
+ Elf_Word symtable_size; // The size of the symbol table
union {
// Transient - Data available while the module is loading
struct {
FILE *_file; // The file object of the open file
- Elf32_Off _cr_offset; // The current offset in the open file
+ Elf_Off _cr_offset; // The current offset in the open file
} l;
// Process execution data
@@ -122,7 +129,7 @@ struct elf_module {
// ELF DT_NEEDED entries for this module
int nr_needed;
- Elf32_Word needed[MAX_NR_DEPS];
+ Elf_Word needed[MAX_NR_DEPS];
};
/**
@@ -157,17 +164,6 @@ struct module_dep {
* This portion is included by the core COM32 module.
*/
-/*
- * Accepted values for various ELF header parameters found in an ELF dynamic
- * object.
- */
-#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules
-#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value
-#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
-#define MODULE_ELF_VERSION EV_CURRENT // Object version
-#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
-#define MODULE_ELF_MACHINE EM_386 // Target architecture
-
/**
* Names of symbols with special meaning (treated as special cases at linking)
*/
@@ -245,7 +241,7 @@ extern int module_load(struct elf_module *module);
* Its current use is to describe the root COM32 module to the rest of the
* module subsystem.
*/
-extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr);
+extern int module_load_shallow(struct elf_module *module, Elf_Addr base_addr);
/**
* module_unload - unloads the module from the system.
@@ -319,7 +315,7 @@ extern struct elf_module *module_find(const char *name);
* If the symbol is found, a pointer to its descriptor structure is returned, and
* NULL otherwise.
*/
-extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module);
+extern Elf_Sym *module_find_symbol(const char *name, struct elf_module *module);
/**
* global_find_symbol - searches for a symbol definition in the entire module namespace.
@@ -336,7 +332,7 @@ extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module
* a pointer to the symbol descriptor structure. If the module parameter is not NULL,
* it is filled with the address of the module descriptor where the symbol is defined.
*/
-extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module);
+extern Elf_Sym *global_find_symbol(const char *name, struct elf_module **module);
/**
* module_get_absolute - converts an memory address relative to a module base address
@@ -346,7 +342,7 @@ extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **modul
*
* The function returns a pointer to the absolute memory address.
*/
-static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
+static inline void *module_get_absolute(Elf_Addr addr, struct elf_module *module) {
return (void*)(module->base_addr + addr);
}
diff --git a/com32/include/sys/x86_64/bitops.h b/com32/include/sys/x86_64/bitops.h
new file mode 100644
index 00000000..7b1cc2b6
--- /dev/null
+++ b/com32/include/sys/x86_64/bitops.h
@@ -0,0 +1,55 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * bitops.h - i386
+ *
+ * Simple bitwise operations
+ */
+
+static inline void set_bit(long __bit, void *__bitmap)
+{
+ asm volatile("bts %1,%0"
+ : "+m" (*(unsigned char *)__bitmap)
+ : "Ir" (__bit) : "memory");
+}
+
+static inline void clr_bit(long __bit, void *__bitmap)
+{
+ asm volatile("btcl %1,%0"
+ : "+m" (*(unsigned char *)__bitmap)
+ : "Ir" (__bit) : "memory");
+}
+
+static inline int __purefunc test_bit(long __bit, const void *__bitmap)
+{
+ unsigned char __r;
+ asm("bt %2,%1; setc %0"
+ : "=qm" (__r)
+ : "m" (*(const unsigned char *)__bitmap), "Ir" (__bit));
+ return __r;
+}
diff --git a/com32/include/sys/x86_64/cpu.h b/com32/include/sys/x86_64/cpu.h
new file mode 100644
index 00000000..89d79154
--- /dev/null
+++ b/com32/include/sys/x86_64/cpu.h
@@ -0,0 +1,148 @@
+#ifndef _CPU_X86_64_H
+#define _CPU_X86_64_H
+
+/* x86_64 cpu.h */
+
+static inline uint64_t rdtsc(void)
+{
+ uint64_t v;
+ asm volatile("rdtsc" : "=A" (v));
+ return v;
+}
+
+static inline uint32_t rdtscl(void)
+{
+ uint32_t v;
+ asm volatile("rdtsc" : "=a" (v) : : "edx");
+ return v;
+}
+
+static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ /* ecx is often an input as well as an output. */
+ asm volatile("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (*eax), "2" (*ecx)
+ : "memory");
+}
+/*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+ * resulting in stale register contents being returned.
+ */
+static inline void cpuid(uint32_t op,
+ uint32_t *eax, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
+{
+ *eax = op;
+ *ecx = 0;
+ native_cpuid(eax, ebx, ecx, edx);
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline uint32_t cpuid_eax(uint32_t op)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ return eax;
+}
+
+static inline uint32_t cpuid_ebx(uint32_t op)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ return ebx;
+}
+
+static inline uint32_t cpuid_ecx(uint32_t op)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ return ecx;
+}
+
+static inline uint32_t cpuid_edx(uint32_t op)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ cpuid(op, &eax, &ebx, &ecx, &edx);
+
+ return edx;
+}
+
+static inline void cpuid_count(uint32_t op, uint32_t cnt,
+ uint32_t * eax, uint32_t * ebx,
+ uint32_t * ecx, uint32_t * edx)
+{
+ asm volatile("movl %%ebx,%1 ; "
+ "cpuid ; "
+ "xchgl %1,%%ebx"
+ : "=a" (*eax), "=SD" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "a"(op), "c"(cnt));
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline __constfunc bool cpu_has_eflag(uint32_t flag)
+{
+ /* x86_64 */
+ uint64_t f0, f1;
+ asm("pushf ; "
+ "pushf ; "
+ "pop %0 ; "
+ "mov %0,%1 ; "
+ "xor %2,%1 ; "
+ "push %1 ; "
+ "popf ; "
+ "pushf ; "
+ "pop %1 ; "
+ "popf"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (flag));
+ return !!((f0^f1) & flag);
+}
+
+static inline uint64_t rdmsr(uint32_t msr)
+{
+ uint64_t v;
+
+ asm volatile("rdmsr" : "=A" (v) : "c"(msr));
+ return v;
+}
+
+static inline void wrmsr(uint64_t v, uint32_t msr)
+{
+ asm volatile("wrmsr" : : "A" (v), "c" (msr));
+}
+
+static inline void cpu_relax(void)
+{
+ asm volatile("rep ; nop");
+}
+
+static inline void hlt(void)
+{
+ asm volatile("hlt");
+}
+
+static inline void cli(void)
+{
+ asm volatile("cli");
+}
+
+static inline void sti(void)
+{
+ asm volatile("sti");
+}
+#endif
diff --git a/com32/include/sys/x86_64/module.h b/com32/include/sys/x86_64/module.h
new file mode 100644
index 00000000..203a6cd0
--- /dev/null
+++ b/com32/include/sys/x86_64/module.h
@@ -0,0 +1,35 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF64 modules definitions and services.
+ */
+
+#ifndef _X86_64_MODULE_H_
+#define _X86_64_MODULE_H_
+
+#include <elf.h>
+
+/*
+ * Accepted values for various ELF header parameters found in an ELF dynamic
+ * object.
+ */
+#define MODULE_ELF_CLASS ELFCLASS64 // 64-bit modules
+#define MODULE_ELF_CLASS_SIZE 64 // Size of a word value
+#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
+#define MODULE_ELF_VERSION EV_CURRENT // Object version
+#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
+#define MODULE_ELF_MACHINE EM_X86_64 // Target architecture
+
+#define ELF_MOD_SYS "64 bit"
+
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Dyn Elf_Dyn;
+typedef Elf64_Word Elf_Word;
+typedef Elf64_Off Elf_Off;
+typedef Elf64_Sym Elf_Sym;
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Phdr Elf_Phdr;
+typedef Elf64_Rel Elf_Rel;
+typedef Elf64_Xword Elf_Bword;
+
+#endif // _X86_64_MODULE_H_
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
new file mode 100644
index 00000000..05f97630
--- /dev/null
+++ b/com32/include/syslinux/firmware.h
@@ -0,0 +1,54 @@
+#ifndef _SYSLINUX_FIRMWARE_H
+#define _SYSLINUX_FIRMWARE_H
+
+#include <syslinux/memscan.h>
+
+struct term_state;
+
+struct output_ops {
+ void (*erase) (int, int, int, int, uint8_t);
+ void (*write_char) (uint8_t, uint8_t);
+ void (*showcursor) (const struct term_state *);
+ void (*scroll_up) (uint8_t, uint8_t, uint8_t);
+ void (*set_cursor) (int, int, bool);
+ void (*beep) (void);
+ void (*get_mode)(int *, int *);
+ void (*set_mode)(uint16_t);
+ void (*get_cursor)(int *, int *);
+};
+
+struct input_ops {
+ char (*getchar)(char *);
+ int (*pollchar)(void);
+};
+
+struct adv_ops {
+ void (*init)(void);
+ int (*write)(void);
+};
+
+struct disk_private;
+struct initramfs;
+struct setup_data;
+
+struct firmware {
+ void (*init)(void);
+ int (*scan_memory)(scan_memory_callback_t, void *);
+ void (*adjust_screen)(void);
+ void (*cleanup)(void);
+ struct disk *(*disk_init)(void *);
+ struct output_ops *o_ops;
+ struct input_ops *i_ops;
+ void (*get_serial_console_info)(uint16_t *, uint16_t *, uint16_t *);
+ bool (*ipappend_strings)(char **, int *);
+ struct adv_ops *adv_ops;
+ int (*boot_linux)(void *, size_t, struct initramfs *,
+ struct setup_data *, char *);
+};
+
+extern struct firmware *firmware;
+
+extern void syslinux_register_bios(void);
+extern void init(void);
+
+#endif /* _SYSLINUX_FIRMWARE_H */
diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h
index f5f95fb0..a8c6f2f5 100644
--- a/com32/include/syslinux/linux.h
+++ b/com32/include/syslinux/linux.h
@@ -37,6 +37,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <klibc/compiler.h>
/* A chunk of an initramfs. These are kept as a doubly-linked
circular list with headnode; the headnode is distinguished by
@@ -68,6 +69,87 @@ struct setup_data {
#define SETUP_E820_EXT 1
#define SETUP_DTB 2
+struct linux_header {
+ uint8_t boot_sector_1[0x0020];
+ uint16_t old_cmd_line_magic;
+ uint16_t old_cmd_line_offset;
+ uint8_t boot_sector_2[0x01f1 - 0x0024];
+ uint8_t setup_sects;
+ uint16_t root_flags;
+ uint32_t syssize;
+ uint16_t ram_size;
+ uint16_t vid_mode;
+ uint16_t root_dev;
+ uint16_t boot_flag;
+ uint16_t jump;
+ uint32_t header;
+ uint16_t version;
+ uint32_t realmode_swtch;
+ uint16_t start_sys;
+ uint16_t kernel_version;
+ uint8_t type_of_loader;
+ uint8_t loadflags;
+ uint16_t setup_move_size;
+ uint32_t code32_start;
+ uint32_t ramdisk_image;
+ uint32_t ramdisk_size;
+ uint32_t bootsect_kludge;
+ uint16_t heap_end_ptr;
+ uint16_t pad1;
+ uint32_t cmd_line_ptr;
+ uint32_t initrd_addr_max;
+ uint32_t kernel_alignment;
+ uint8_t relocatable_kernel;
+ uint8_t pad2[3];
+ uint32_t cmdline_max_len;
+ uint32_t hardware_subarch;
+ uint64_t hardware_subarch_data;
+ uint32_t payload_offset;
+ uint32_t payload_length;
+ uint64_t setup_data;
+ uint64_t pref_address;
+ uint32_t init_size;
+} __packed;
+
+struct screen_info {
+ uint8_t orig_x; /* 0x00 */
+ uint8_t orig_y; /* 0x01 */
+ uint16_t ext_mem_k; /* 0x02 */
+ uint16_t orig_video_page; /* 0x04 */
+ uint8_t orig_video_mode; /* 0x06 */
+ uint8_t orig_video_cols; /* 0x07 */
+ uint8_t flags; /* 0x08 */
+ uint8_t unused2; /* 0x09 */
+ uint16_t orig_video_ega_bx;/* 0x0a */
+ uint16_t unused3; /* 0x0c */
+ uint8_t orig_video_lines; /* 0x0e */
+ uint8_t orig_video_isVGA; /* 0x0f */
+ uint16_t orig_video_points;/* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ uint16_t lfb_width; /* 0x12 */
+ uint16_t lfb_height; /* 0x14 */
+ uint16_t lfb_depth; /* 0x16 */
+ uint32_t lfb_base; /* 0x18 */
+ uint32_t lfb_size; /* 0x1c */
+ uint16_t cl_magic, cl_offset; /* 0x20 */
+ uint16_t lfb_linelength; /* 0x24 */
+ uint8_t red_size; /* 0x26 */
+ uint8_t red_pos; /* 0x27 */
+ uint8_t green_size; /* 0x28 */
+ uint8_t green_pos; /* 0x29 */
+ uint8_t blue_size; /* 0x2a */
+ uint8_t blue_pos; /* 0x2b */
+ uint8_t rsvd_size; /* 0x2c */
+ uint8_t rsvd_pos; /* 0x2d */
+ uint16_t vesapm_seg; /* 0x2e */
+ uint16_t vesapm_off; /* 0x30 */
+ uint16_t pages; /* 0x32 */
+ uint16_t vesa_attributes; /* 0x34 */
+ uint32_t capabilities; /* 0x36 */
+ uint8_t _reserved[6]; /* 0x3a */
+} __packed;
+
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
struct initramfs *initramfs,
struct setup_data *setup_data,
@@ -89,6 +171,23 @@ int initramfs_load_file(struct initramfs *ihead, const char *src_filename,
int initramfs_add_trailer(struct initramfs *ihead);
int initramfs_load_archive(struct initramfs *ihead, const char *filename);
+/* Get the combined size of the initramfs */
+static inline uint32_t initramfs_size(struct initramfs *initramfs)
+{
+ struct initramfs *ip;
+ uint32_t size = 0;
+
+ if (!initramfs)
+ return 0;
+
+ for (ip = initramfs->next; ip->len; ip = ip->next) {
+ size = (size + ip->align - 1) & ~(ip->align - 1); /* Alignment */
+ size += ip->len;
+ }
+
+ return size;
+}
+
/* Setup data manipulation functions */
struct setup_data *setup_data_init(void);
diff --git a/com32/include/syslinux/memscan.h b/com32/include/syslinux/memscan.h
index db795439..c3ebf847 100644
--- a/com32/include/syslinux/memscan.h
+++ b/com32/include/syslinux/memscan.h
@@ -34,5 +34,6 @@
typedef int (*scan_memory_callback_t) (void *, addr_t, addr_t, bool);
int syslinux_scan_memory(scan_memory_callback_t callback, void *data);
+int bios_scan_memory(scan_memory_callback_t callback, void *data);
#endif /* _SYSLINUX_MEMSCAN_H */
diff --git a/com32/include/syslinux/version.h b/com32/include/syslinux/version.h
new file mode 100644
index 00000000..762db371
--- /dev/null
+++ b/com32/include/syslinux/version.h
@@ -0,0 +1,6 @@
+#ifndef _SYSLINUX_VERSION_H
+#define _SYSLINUX_VERSION_H
+
+#define __STDC_VERSION__ 200000L
+
+#endif /* _SYSLINUX_VERSION_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 5d270a49..705feb3f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -17,24 +17,25 @@ LIBPNG_OBJS = \
libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \
libpng/pngerror.o libpng/pngpread.o
-# ZIP library object files
-LIBZLIB_OBJS = \
- zlib/adler32.o zlib/compress.o zlib/crc32.o \
- zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \
- zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o \
- sys/zfile.o sys/zfopen.o
-
# JPG library object files
LIBJPG_OBJS = \
jpeg/tinyjpeg.o jpeg/jidctflt.o jpeg/decode1.o jpeg/decode3.o \
jpeg/rgb24.o jpeg/bgr24.o jpeg/yuv420p.o jpeg/grey.o \
jpeg/rgba32.o jpeg/bgra32.o
+ifndef EFI_BUILD
LIBVESA_OBJS = \
sys/vesacon_write.o sys/vesaserial_write.o \
sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \
sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o \
sys/vesa/i915resolution.o
+else
+LIBVESA_OBJS = \
+ sys/vesacon_write.o sys/vesaserial_write.o \
+ sys/vesa/efi/initvesa.o sys/vesa/efi/drawtxt.o sys/vesa/efi/background.o \
+ sys/vesa/alphatbl.o sys/vesa/efi/screencpy.o sys/vesa/efi/fmtpixel.o \
+ sys/vesa/efi/i915resolution.o
+endif
LIBMISC_OBJS = \
sys/libansi.o sys/gpxe.o
@@ -51,134 +52,9 @@ LIBSYSLINUX_OBJS = \
syslinux/pxe_dns.o \
syslinux/video/fontquery.o syslinux/video/reportmode.o
-LIBLOAD_OBJS = \
- syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \
- syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \
- syslinux/shuffle_rm.o syslinux/zonelist.o \
- syslinux/dump_mmap.o syslinux/dump_movelist.o \
- \
- syslinux/run_default.o syslinux/run_command.o \
- syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \
- \
- syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \
- \
- syslinux/load_linux.o syslinux/initramfs.o \
- syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \
- syslinux/initramfs_archive.o
-
DYNENTRY_OBJS = \
atexit.o onexit.o abort.o
-## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE
-LIBENTRY_OBJS = \
- sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o \
- sys/argv.o sys/sleep.o \
- sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
- sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \
- sys/openmem.o \
- sys/isatty.o sys/fstat.o \
- \
- dprintf.o vdprintf.o \
- \
- syslinux/idle.o \
- \
- exit.o
-
-LIBMODULE_OBJS = \
- sys/module/common.o sys/module/elf_module.o \
- sys/module/shallow_module.o sys/module/elfutils.o \
- sys/module/exec.o
-
-LIBGCC_OBJS = \
- libgcc/__ashldi3.o libgcc/__udivdi3.o \
- libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
- libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
- libgcc/__divdi3.o libgcc/__moddi3.o
-
-LIBCONSOLE_OBJS = \
- \
- sys/openconsole.o sys/line_input.o \
- sys/colortable.o sys/screensize.o \
- \
- sys/stdcon_read.o sys/rawcon_read.o \
- sys/rawcon_write.o \
- sys/null_write.o sys/serial_write.o \
- \
- sys/xserial_write.o \
- \
- sys/ansi.o \
- \
- sys/ansicon_write.o sys/ansiserial_write.o \
- \
- syslinux/serial.o
-
-LIBOTHER_OBJS = \
- atoi.o atol.o atoll.o calloc.o creat.o \
- fgets.o fprintf.o fputc.o \
- putchar.o \
- getopt.o getopt_long.o \
- lrand48.o stack.o memccpy.o memchr.o \
- mempcpy.o memmem.o memmove.o memswap.o \
- perror.o qsort.o seed48.o \
- srand48.o sscanf.o strcasecmp.o strcat.o \
- strerror.o \
- strnlen.o \
- strncat.o strndup.o \
- stpncpy.o \
- strntoimax.o strntoumax.o strsep.o strspn.o strstr.o \
- strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o \
- strtoumax.o vprintf.o vsprintf.o \
- asprintf.o vasprintf.o \
- vsscanf.o \
- skipspace.o \
- chrreplace.o \
- bufprintf.o \
- inet.o dhcppack.o dhcpunpack.o \
- strreplace.o \
- lstrdup.o \
- \
- suffix_number.o \
- \
- getcwd.o fdopendir.o \
- \
- sys/line_input.o \
- sys/colortable.o sys/screensize.o \
- \
- sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
- sys/rawcon_write.o \
- sys/null_read.o sys/null_write.o sys/serial_write.o \
- \
- sys/xserial_write.o \
- \
- sys/ansi.o \
- \
- sys/ansicon_write.o sys/ansiserial_write.o \
- \
- pci/cfgtype.o pci/scan.o pci/bios.o \
- pci/readb.o pci/readw.o pci/readl.o \
- pci/writeb.o pci/writew.o pci/writel.o \
- \
- sys/x86_init_fpu.o math/pow.o math/strtod.o \
- syslinux/disk.o \
- \
- syslinux/setup_data.o
-
-CORELIBOBJS = \
- memcpy.o memset.o memcmp.o printf.o strncmp.o vfprintf.o \
- strlen.o vsnprintf.o snprintf.o stpcpy.o strcmp.o strdup.o \
- strcpy.o strncpy.o setjmp.o fopen.o fread.o fread2.o puts.o \
- sprintf.o strlcat.o strchr.o strlcpy.o strncasecmp.o ctypes.o \
- fputs.o fwrite2.o fwrite.o fgetc.o fclose.o errno.o lmalloc.o \
- sys/err_read.o sys/err_write.o sys/null_read.o \
- sys/stdcon_write.o sys/openconsole.o \
- syslinux/memscan.o strrchr.o \
- libgcc/__ashldi3.o libgcc/__udivdi3.o \
- libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
- libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
- libgcc/__divdi3.o libgcc/__moddi3.o \
- $(LIBENTRY_OBJS) \
- $(LIBMODULE_OBJS)
-
MINLIBOBJS = \
syslinux/ipappend.o \
syslinux/dsinfo.o \
@@ -189,7 +65,6 @@ MINLIBOBJS = \
$(LIBZLIB_OBJS)
# $(LIBVESA_OBJS)
-
DYNLIBOBJS = \
$(LIBZLIB_OBJS) \
$(LIBPNG_OBJS) \
@@ -244,7 +119,12 @@ install: all
cp -r ../include $(INSTALLROOT)$(COM32DIR)
# These files are performance critical, and doesn't compile well with -Os
+#FIXME: determine if drawtxt.c is really EFI-dependent
+#ifndef EFI_BUILD
sys/vesa/drawtxt.o: sys/vesa/drawtxt.c
+#else
+sys/vesa/efi/drawtxt.o: sys/vesa/efi/drawtxt.c
+#endif
$(CC) $(MAKEDEPS) $(CFLAGS) -O3 -c -o $@ $<
sys/vesa/alphatbl.c: sys/vesa/alphatbl.pl
diff --git a/com32/lib/i386/elf.ld b/com32/lib/i386/elf.ld
new file mode 100644
index 00000000..158badbb
--- /dev/null
+++ b/com32/lib/i386/elf.ld
@@ -0,0 +1,184 @@
+/*
+ * Linker script for ELF dynamic loaded modules.
+ */
+
+/* Script for --shared -z combreloc: shared library, combine & sort relocs */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0 + SIZEOF_HEADERS;
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ . = ALIGN(4);
+ .preinit_array :
+ {
+ KEEP (*(.preinit_array))
+ }
+ .init_array :
+ {
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ }
+ .fini_array :
+ {
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ }
+
+ .ctors :
+ {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ LONG(0x00000000)
+ __module_init_ptr = .;
+ KEEP (*(.ctors_modinit))
+ LONG(0x00000000)
+ __module_main_ptr = .;
+ KEEP (*(.ctors_modmain))
+ LONG(0x00000000)
+ }
+
+ .dtors :
+ {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ LONG(0x00000000)
+ __module_exit_ptr = .;
+ KEEP (*(.dtors_modexit))
+ LONG(0x00000000)
+ }
+
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) }
+ /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */
+ .got.plt : { *(.got.plt) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ PROVIDE (edata = .);
+ PROVIDE (_edata = .);
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ PROVIDE (_end = .);
+ PROVIDE (end = .);
+ /*. = DATA_SEGMENT_END (.); -> This gives a "invalid assignment to location counter" error */
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.eh_frame) }
+}
diff --git a/com32/lib/i386/setjmp.S b/com32/lib/i386/setjmp.S
new file mode 100644
index 00000000..658df485
--- /dev/null
+++ b/com32/lib/i386/setjmp.S
@@ -0,0 +1,63 @@
+/*
+ * arch/i386/setjmp.S
+ *
+ * setjmp/longjmp for the i386 architecture
+ *
+ *
+ *
+ * The jmp_buf is assumed to contain the following, in order:
+ * %ebx
+ * %esp
+ * %ebp
+ * %esi
+ * %edi
+ * <return address>
+ */
+
+ .text
+ .align 4
+
+ .globl _setjmp
+ .type _setjmp, @function
+_setjmp: # gcc 4.0.1 wants this as an alias?
+
+ .globl setjmp
+ .type setjmp, @function
+setjmp:
+#ifdef REGPARM
+ movl %eax,%edx
+#else
+ movl 4(%esp),%edx
+#endif
+ popl %ecx # Return address, and adjust the stack
+ xorl %eax,%eax # Return value
+ movl %ebx,(%edx)
+ movl %esp,4(%edx) # Post-return %esp!
+ pushl %ecx # Make the call/return stack happy
+ movl %ebp,8(%edx)
+ movl %esi,12(%edx)
+ movl %edi,16(%edx)
+ movl %ecx,20(%edx) # Return address
+ ret
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+#ifdef REGPARM
+ xchgl %eax,%edx
+#else
+ movl 4(%esp),%edx # jmp_ptr address
+ movl 8(%esp),%eax # Return value
+#endif
+ movl (%edx),%ebx
+ movl 4(%edx),%esp
+ movl 8(%edx),%ebp
+ movl 12(%edx),%esi
+ movl 16(%edx),%edi
+ jmp *20(%edx)
+
+ .size longjmp,.-longjmp
diff --git a/com32/lib/libgcc/__muldi3.S b/com32/lib/libgcc/__muldi3.S
index 648a88ad..424787c8 100644
--- a/com32/lib/libgcc/__muldi3.S
+++ b/com32/lib/libgcc/__muldi3.S
@@ -9,6 +9,8 @@
.globl __muldi3
.type __muldi3,@function
__muldi3:
+#if __SIZEOF_POINTER__ == 4
+ /* i386 */
push %esi
#ifndef REGPARM
movl 8(%esp),%eax
@@ -31,4 +33,51 @@ __muldi3:
#endif
pop %esi
ret
+#elif __SIZEOF_POINTER__ == 8
+ /* x86_64 */
+ push %rsi
+#ifndef REGPARM
+/*
+ movl 8(%esp),%eax
+ movl %eax,%esi
+ movl 16(%esp),%ecx
+ mull %ecx
+ imull 12(%esp),%ecx
+ imull 20(%esp),%esi
+ addl %ecx,%edx
+ addl %esi,%edx
+*/
+ movq 8(%rsp),%rax
+ movq %rax,%rsi
+ movq 16(%rsp),%rcx
+ mulq %rcx
+ imulq 12(%rsp),%rcx
+ imulq 20(%rsp),%rsi
+ addq %rcx,%rdx
+ addq %rsi,%rdx
+#else
+/*
+ movl %eax,%esi
+ push %edx
+ mull %ecx
+ imull 8(%esp),%esi
+ addl %esi,%edx
+ pop %rsi
+ imull %esi,%ecx
+ addl %ecx,%edx
+*/
+ movq %rax,%rsi
+ pushq %rdx
+ mulq %rcx
+ imulq 8(%rsp),%rsi
+ addq %rsi,%rdx
+ popq %rsi
+ imulq %rsi,%rcx
+ addq %rcx,%rdx
+#endif
+ pop %rsi
+ ret
+#else
+#error "Unsupported architecture for __muldi3.S"
+#endif
.size __muldi3,.-__muldi3
diff --git a/com32/lib/memcpy.S b/com32/lib/memcpy.S
index 6b986a0d..9b5306dd 100644
--- a/com32/lib/memcpy.S
+++ b/com32/lib/memcpy.S
@@ -36,6 +36,10 @@
.globl memcpy
.type memcpy, @function
memcpy:
+ movl 0xc(%esp),%ecx
+ movl 0x8(%esp),%edx
+ movl 0x4(%esp),%eax
+
jecxz 1f
pushl %esi
diff --git a/com32/lib/memcpy.c b/com32/lib/memcpy.c
new file mode 100644
index 00000000..5ce206d0
--- /dev/null
+++ b/com32/lib/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb":"+c" (nl),
+ "+S"(p), "+D"(q)
+ :"r"(n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb":"+c"
+ (nq), "+S"(p), "+D"(q)
+ :"r"((uint32_t) (n & 7)));
+#else
+ while (n--) {
+ *q++ = *p++;
+ }
+#endif
+
+ return dst;
+}
diff --git a/com32/lib/memmove.S b/com32/lib/memmove.S
index e97299f2..2094e4aa 100644
--- a/com32/lib/memmove.S
+++ b/com32/lib/memmove.S
@@ -37,6 +37,10 @@
.type memmove,@function
.text
memmove:
+ movl 0xc(%esp),%ecx
+ movl 0x8(%esp),%edx
+ movl 0x4(%esp),%eax
+
jecxz 4f
pushl %esi
diff --git a/com32/lib/memmove.c b/com32/lib/memmove.c
new file mode 100644
index 00000000..a398cd8d
--- /dev/null
+++ b/com32/lib/memmove.c
@@ -0,0 +1,36 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+ if (q < p) {
+ asm volatile("cld; rep; movsb"
+ : "+c" (n), "+S"(p), "+D"(q));
+ } else {
+ p += (n - 1);
+ q += (n - 1);
+ asm volatile("std; rep; movsb; cld"
+ : "+c" (n), "+S"(p), "+D"(q));
+ }
+#else
+ if (q < p) {
+ while (n--) {
+ *q++ = *p++;
+ }
+ } else {
+ p += n;
+ q += n;
+ while (n--) {
+ *--q = *--p;
+ }
+ }
+#endif
+
+ return dst;
+}
diff --git a/com32/lib/mempcpy.S b/com32/lib/mempcpy.S
index cad7b983..2096f132 100644
--- a/com32/lib/mempcpy.S
+++ b/com32/lib/mempcpy.S
@@ -36,6 +36,10 @@
.globl mempcpy
.type mempcpy, @function
mempcpy:
+ movl 0xc(%esp),%ecx
+ movl 0x8(%esp),%edx
+ movl 0x4(%esp),%eax
+
jecxz 1f
pushl %esi
diff --git a/com32/lib/mempcpy.c b/com32/lib/mempcpy.c
new file mode 100644
index 00000000..be23b667
--- /dev/null
+++ b/com32/lib/mempcpy.c
@@ -0,0 +1,14 @@
+/*
+ * mempcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+/* simply a wrapper around memcpy implementation */
+
+void *mempcpy(void *dst, const void *src, size_t n)
+{
+
+ return (char *)memcpy(dst, src, n) + n;
+}
diff --git a/com32/lib/memset.S b/com32/lib/memset.S
index e641415d..fd42842a 100644
--- a/com32/lib/memset.S
+++ b/com32/lib/memset.S
@@ -36,6 +36,10 @@
.type memset,@function
.text
memset:
+ movl 0xc(%esp),%ecx
+ movl 0x8(%esp),%edx
+ movl 0x4(%esp),%eax
+
jecxz 6f
pushl %edi
diff --git a/com32/lib/memset.c b/com32/lib/memset.c
new file mode 100644
index 00000000..aa00b5b1
--- /dev/null
+++ b/com32/lib/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+ char *q = dst;
+
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile ("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+ : "+c" (nl), "+D" (q)
+ : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile ("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+ :"+c" (nq), "+D" (q)
+ : "a" ((unsigned char)c * 0x0101010101010101U),
+ "r" ((uint32_t) n & 7));
+#else
+ while (n--) {
+ *q++ = c;
+ }
+#endif
+
+ return dst;
+}
diff --git a/com32/lib/setjmp.S b/com32/lib/setjmp.S
index 658df485..2fb5c234 100644
--- a/com32/lib/setjmp.S
+++ b/com32/lib/setjmp.S
@@ -13,7 +13,7 @@
* %edi
* <return address>
*/
-
+/*
.text
.align 4
@@ -61,3 +61,12 @@ longjmp:
jmp *20(%edx)
.size longjmp,.-longjmp
+*/
+#if __SIZEOF_POINTER__ == 4
+#include <i386/setjmp.S>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/setjmp.S>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
+
diff --git a/com32/lib/sys/ansi.c b/com32/lib/sys/ansi.c
index f73c03e2..db47ea46 100644
--- a/com32/lib/sys/ansi.c
+++ b/com32/lib/sys/ansi.c
@@ -438,6 +438,14 @@ void __ansi_putchar(const struct term_info *ti, uint8_t ch)
op->scroll_up(st);
}
+ /*
+ * Testing on EFI shows that from (rows-1)th line newline does not
+ * advance anymore. All further output is always on the same
+ * (rows-1)th line. Resetting the row to 0 does work.
+ */
+ if (xy.y == rows-1)
+ xy.y = 0;
+
/* Update cursor position */
op->set_cursor(xy.x, xy.y, st->cursor);
st->xy = xy;
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index e5483fbc..74add717 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -35,13 +35,13 @@
#include <errno.h>
#include <string.h>
-#include <com32.h>
#include <minmax.h>
#include <colortbl.h>
#include <klibc/compiler.h>
#include <syslinux/config.h>
#include "file.h"
#include "ansi.h"
+#include <syslinux/firmware.h>
#include "graphics.h"
static void ansicon_erase(const struct term_state *, int, int, int, int);
@@ -66,23 +66,15 @@ static struct term_info ti = {
.op = &__ansicon_ops
};
-#define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
-#define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
-#define BIOS_COLS (*(uint16_t *)0x44A)
-#define BIOS_PAGE (*(uint8_t *)0x462)
+#define TEXT_MODE 0x0005
/* Reference counter to the screen, to keep track of if we need
reinitialization. */
static int ansicon_counter = 0;
-static uint16_t cursor_type; /* Saved cursor pattern */
-
/* Common setup */
int __ansicon_open(struct file_info *fp)
{
- static com32sys_t ireg; /* Auto-initalized to all zero */
- com32sys_t oreg;
-
if (!ansicon_counter) {
/* Are we disabled? */
if (syslinux_serial_console_info()->flowctl & 0x8000) {
@@ -91,20 +83,14 @@ int __ansicon_open(struct file_info *fp)
ti.cols = 80;
} else {
/* Force text mode */
- syslinux_force_text_mode();
+ firmware->o_ops->set_mode(TEXT_MODE);
/* Initial state */
- ti.rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
- ti.cols = BIOS_COLS;
+ firmware->o_ops->get_mode(&ti.cols, &ti.rows);
__ansi_init(&ti);
/* Get cursor shape and position */
- ireg.eax.b[1] = 0x03;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, &oreg);
- cursor_type = oreg.ecx.w[0];
- ti.ts->xy.x = oreg.edx.b[0];
- ti.ts->xy.y = oreg.edx.b[1];
+ firmware->o_ops->get_cursor(&ti.ts->xy.x, &ti.ts->xy.y);
}
}
@@ -155,69 +141,45 @@ static uint8_t ansicon_attribute(const struct term_state *st)
static void ansicon_erase(const struct term_state *st,
int x0, int y0, int x1, int y1)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0600; /* Clear window */
- ireg.ebx.b[1] = ansicon_attribute(st);
- ireg.ecx.b[0] = x0;
- ireg.ecx.b[1] = y0;
- ireg.edx.b[0] = x1;
- ireg.edx.b[1] = y1;
- __intcall(0x10, &ireg, NULL);
+ uint8_t attribute = ansicon_attribute(st);
+
+ if (firmware->o_ops->erase)
+ firmware->o_ops->erase(x0, y0, x1, y1, attribute);
}
/* Show or hide the cursor */
static void ansicon_showcursor(const struct term_state *st)
{
- static com32sys_t ireg;
-
- ireg.eax.b[1] = 0x01;
- ireg.ecx.w[0] = st->cursor ? cursor_type : 0x2020;
- __intcall(0x10, &ireg, NULL);
+ firmware->o_ops->showcursor(st);
}
static void ansicon_set_cursor(int x, int y, bool visible)
{
- const int page = BIOS_PAGE;
- struct curxy xy = BIOS_CURXY[page];
- static com32sys_t ireg;
-
- (void)visible;
-
- if (xy.x != x || xy.y != y) {
- ireg.eax.b[1] = 0x02;
- ireg.ebx.b[1] = page;
- ireg.edx.b[1] = y;
- ireg.edx.b[0] = x;
- __intcall(0x10, &ireg, NULL);
- }
+ firmware->o_ops->set_cursor(x, y, visible);
}
static void ansicon_write_char(int x, int y, uint8_t ch,
const struct term_state *st)
{
- static com32sys_t ireg;
-
+ uint8_t attribute = ansicon_attribute(st);
ansicon_set_cursor(x, y, false);
- ireg.eax.b[1] = 0x09;
- ireg.eax.b[0] = ch;
- ireg.ebx.b[1] = BIOS_PAGE;
- ireg.ebx.b[0] = ansicon_attribute(st);
- ireg.ecx.w[0] = 1;
- __intcall(0x10, &ireg, NULL);
+ firmware->o_ops->write_char(ch, attribute);
}
static void ansicon_scroll_up(const struct term_state *st)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0601;
- ireg.ebx.b[1] = ansicon_attribute(st);
- ireg.ecx.w[0] = 0;
- ireg.edx.b[1] = ti.rows - 1;
- ireg.edx.b[0] = ti.cols - 1;
- __intcall(0x10, &ireg, NULL); /* Scroll */
+ uint8_t rows, cols, attribute;
+
+ /*
+ * Earlier code set ti.cols to 1 causing console output one char
+ * per line.
+ */
+ cols = 1;
+ rows = ti.rows - 1;
+ attribute = ansicon_attribute(st);
+
+ firmware->o_ops->scroll_up(cols, rows, attribute);
}
ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
@@ -240,11 +202,8 @@ ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
void __ansicon_beep(void)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0e07;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, NULL);
+ if (firmware->o_ops->beep)
+ firmware->o_ops->beep();
}
const struct output_dev dev_ansicon_w = {
diff --git a/com32/lib/sys/farcall.c b/com32/lib/sys/farcall.c
index 988ee6d2..2749083e 100644
--- a/com32/lib/sys/farcall.c
+++ b/com32/lib/sys/farcall.c
@@ -6,9 +6,17 @@
static inline uint32_t eflags(void)
{
- uint32_t v;
+ //uint32_t v;
+#if __SIZEOF_POINTER__ == 4
+ uint32_t v;
asm volatile("pushfl ; popl %0" : "=rm" (v));
+#elif __SIZEOF_POINTER__ == 8
+ uint64_t v;
+ asm volatile("pushfq ; pop %0" : "=rm" (v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
return v;
}
diff --git a/com32/lib/sys/i386/x86_init_fpu.c b/com32/lib/sys/i386/x86_init_fpu.c
new file mode 100644
index 00000000..cf336932
--- /dev/null
+++ b/com32/lib/sys/i386/x86_init_fpu.c
@@ -0,0 +1,58 @@
+/*
+ * x86_has_fpu.c
+ *
+ * Test for an x86 FPU, and do any necessary setup.
+ */
+
+#include <inttypes.h>
+#include <sys/fpu.h>
+
+static inline uint64_t get_cr0(void)
+{
+ uint32_t v;
+asm("movl %%cr0,%0":"=r"(v));
+ return v;
+}
+
+static inline void set_cr0(uint32_t v)
+{
+ asm volatile ("movl %0,%%cr0"::"r" (v));
+}
+
+#define CR0_PE 0x00000001
+#define CR0_MP 0x00000002
+#define CR0_EM 0x00000004
+#define CR0_TS 0x00000008
+#define CR0_ET 0x00000010
+#define CR0_NE 0x00000020
+#define CR0_WP 0x00010000
+#define CR0_AM 0x00040000
+#define CR0_NW 0x20000000
+#define CR0_CD 0x40000000
+#define CR0_PG 0x80000000
+
+int x86_init_fpu(void)
+{
+ uint32_t cr0;
+ uint16_t fsw = 0xffff;
+ uint16_t fcw = 0xffff;
+
+ cr0 = get_cr0();
+ cr0 &= ~(CR0_EM | CR0_TS);
+ cr0 |= CR0_MP;
+ set_cr0(cr0);
+
+ asm volatile ("fninit");
+ asm volatile ("fnstsw %0":"+m" (fsw));
+ if (fsw != 0)
+ return -1;
+
+ asm volatile ("fnstcw %0":"+m" (fcw));
+ if ((fcw & 0x103f) != 0x3f)
+ return -1;
+
+ /* Techically, this could be a 386 with a 287. We could add a check
+ for that here... */
+
+ return 0;
+}
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 002b733a..bc058a66 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -23,7 +23,7 @@ LIST_HEAD(modules_head);
// User-space debugging routines
#ifdef ELF_DEBUG
-void print_elf_ehdr(Elf32_Ehdr *ehdr) {
+void print_elf_ehdr(Elf_Ehdr *ehdr) {
int i;
fprintf(stderr, "Identification:\t");
@@ -38,18 +38,18 @@ void print_elf_ehdr(Elf32_Ehdr *ehdr) {
fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
//fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
- //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf32_Ehdr));
+ //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf_Ehdr));
fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
ehdr->e_shnum);
}
void print_elf_symbols(struct elf_module *module) {
unsigned int i;
- Elf32_Sym *crt_sym;
+ Elf_Sym *crt_sym;
for (i = 1; i < module->symtable_size; i++)
{
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+ crt_sym = (Elf_Sym*)(module->sym_table + i*module->syment_size);
fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
@@ -159,7 +159,7 @@ int image_skip(size_t size, struct elf_module *module) {
return 0;
}
-int image_seek(Elf32_Off offset, struct elf_module *module) {
+int image_seek(Elf_Off offset, struct elf_module *module) {
if (offset < module->u.l._cr_offset) // Cannot seek backwards
return -1;
@@ -214,9 +214,14 @@ struct elf_module *module_find(const char *name) {
}
+// Mouli: This is checking the header for 32bit machine
+// Support 64bit architecture as well.
+// Parts of the ELF header checked are common to both ELF32 and ELF64
+// Adding simple checks for both 32bit and 64bit should work (hopefully)
+//
// Performs verifications on ELF header to assure that the open file is a
// valid SYSLINUX ELF module.
-int check_header_common(Elf32_Ehdr *elf_hdr) {
+int check_header_common(Elf_Ehdr *elf_hdr) {
// Check the header magic
if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
@@ -227,7 +232,8 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+ if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 &&
+ elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
DBG_PRINT("Invalid ELF class code\n");
return -1;
}
@@ -243,7 +249,8 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+ if (elf_hdr->e_machine != EM_386 &&
+ elf_hdr->e_machine != EM_X86_64) {
DBG_PRINT("Invalid ELF architecture\n");
return -1;
}
@@ -252,6 +259,7 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
}
+
int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
struct module_dep *crt_dep;
struct module_dep *new_dep;
@@ -308,7 +316,7 @@ int clear_dependency(struct elf_module *req, struct elf_module *dep) {
int check_symbols(struct elf_module *module)
{
unsigned int i;
- Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
+ Elf_Sym *crt_sym = NULL, *ref_sym = NULL;
char *crt_name;
struct elf_module *crt_module;
@@ -356,7 +364,6 @@ int check_symbols(struct elf_module *module)
if (strong_count == 0 && weak_count == 0)
{
DBG_PRINT("Symbol %s is undefined\n", crt_name);
- printf("Undef symbol FAIL: %s\n",crt_name);
return -1;
}
}
@@ -422,18 +429,18 @@ int module_unload(struct elf_module *module) {
return _module_unload(module);
}
-static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
+static Elf_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
unsigned long h = elf_hash((const unsigned char*)name);
- Elf32_Word *cr_word = module->hash_table;
+ Elf_Word *cr_word = module->hash_table;
- Elf32_Word nbucket = *cr_word++;
+ Elf_Word nbucket = *cr_word++;
cr_word++; // Skip nchain
- Elf32_Word *bkt = cr_word;
- Elf32_Word *chn = cr_word + nbucket;
+ Elf_Word *bkt = cr_word;
+ Elf_Word *chn = cr_word + nbucket;
- Elf32_Word crt_index = bkt[h % module->hash_table[0]];
- Elf32_Sym *crt_sym;
+ Elf_Word crt_index = bkt[h % module->hash_table[0]];
+ Elf_Sym *crt_sym;
while (crt_index != STN_UNDEF) {
@@ -448,32 +455,32 @@ static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *m
return NULL;
}
-static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+static Elf_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
unsigned long h = elf_gnu_hash((const unsigned char*)name);
// Setup code (TODO: Optimize this by computing only once)
- Elf32_Word *cr_word = module->ghash_table;
- Elf32_Word nbucket = *cr_word++;
- Elf32_Word symbias = *cr_word++;
- Elf32_Word bitmask_nwords = *cr_word++;
+ Elf_Word *cr_word = module->ghash_table;
+ Elf_Word nbucket = *cr_word++;
+ Elf_Word symbias = *cr_word++;
+ Elf_Word bitmask_nwords = *cr_word++;
if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
DBG_PRINT("Invalid GNU Hash structure\n");
return NULL;
}
- Elf32_Word gnu_shift = *cr_word++;
+ Elf_Word gnu_shift = *cr_word++;
- Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
+ Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word;
cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
- Elf32_Word *gnu_buckets = cr_word;
+ Elf_Word *gnu_buckets = cr_word;
cr_word += nbucket;
- Elf32_Word *gnu_chain_zero = cr_word - symbias;
+ Elf_Word *gnu_chain_zero = cr_word - symbias;
// Computations
- Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+ Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
(bitmask_nwords - 1)];
unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
@@ -481,18 +488,18 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo
if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
unsigned long rem;
- Elf32_Word bucket;
+ Elf_Word bucket;
rem = h % nbucket;
bucket = gnu_buckets[rem];
if (bucket != 0) {
- const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
+ const Elf_Word* hasharr = &gnu_chain_zero[bucket];
do {
if (((*hasharr ^ h ) >> 1) == 0) {
- Elf32_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
+ Elf_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
return crt_sym;
@@ -505,11 +512,11 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo
return NULL;
}
-static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
+static Elf_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
{
unsigned int i;
- Elf32_Sym *crt_sym;
+ Elf_Sym *crt_sym;
for (i=1; i < module->symtable_size; i++)
{
@@ -523,8 +530,8 @@ static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module
return NULL;
}
-Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
- Elf32_Sym *result = NULL;
+Elf_Sym *module_find_symbol(const char *name, struct elf_module *module) {
+ Elf_Sym *result = NULL;
if (module->ghash_table != NULL)
result = module_find_symbol_gnu(name, module);
@@ -546,10 +553,10 @@ Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
return result;
}
-Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+Elf_Sym *global_find_symbol(const char *name, struct elf_module **module) {
struct elf_module *crt_module;
- Elf32_Sym *crt_sym = NULL;
- Elf32_Sym *result = NULL;
+ Elf_Sym *crt_sym = NULL;
+ Elf_Sym *result = NULL;
for_each_module(crt_module) {
crt_sym = module_find_symbol(name, crt_module);
diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h
index 54f0ec4b..652c9735 100644
--- a/com32/lib/sys/module/common.h
+++ b/com32/lib/sys/module/common.h
@@ -15,7 +15,6 @@
#include "elfutils.h"
-
// Performs an operation and jumps to a given label if an error occurs
#define CHECKED(res, expr, error) \
do { \
@@ -27,12 +26,12 @@
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
-static inline Elf32_Sym *symbol_get_entry(struct elf_module *module, int entry)
+static inline Elf_Sym *symbol_get_entry(struct elf_module *module, int entry)
{
char *sym_table = (char *)module->sym_table;
int index = entry * module->syment_size;
- return (Elf32_Sym *)(sym_table + index);
+ return (Elf_Sym *)(sym_table + index);
}
//#define ELF_DEBUG
@@ -45,7 +44,7 @@ static inline Elf32_Sym *symbol_get_entry(struct elf_module *module, int entry)
// User-space debugging routines
#ifdef ELF_DEBUG
-extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_ehdr(Elf_Ehdr *ehdr);
extern void print_elf_symbols(struct elf_module *module);
#endif //ELF_DEBUG
@@ -58,11 +57,11 @@ extern int image_load(struct elf_module *module);
extern int image_unload(struct elf_module *module);
extern int image_read(void *buff, size_t size, struct elf_module *module);
extern int image_skip(size_t size, struct elf_module *module);
-extern int image_seek(Elf32_Off offset, struct elf_module *module);
+extern int image_seek(Elf_Off offset, struct elf_module *module);
extern struct module_dep *module_dep_alloc(struct elf_module *module);
-extern int check_header_common(Elf32_Ehdr *elf_hdr);
+extern int check_header_common(Elf_Ehdr *elf_hdr);
extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h
index a901ff48..91bdcb3f 100644
--- a/com32/lib/sys/module/elfutils.h
+++ b/com32/lib/sys/module/elfutils.h
@@ -3,23 +3,24 @@
#include <elf.h>
#include <stdlib.h>
+#include <sys/module.h>
/**
* elf_get_header - Returns a pointer to the ELF header structure.
* @elf_image: pointer to the ELF file image in memory
*/
-static inline Elf32_Ehdr *elf_get_header(void *elf_image) {
- return (Elf32_Ehdr*)elf_image;
+static inline Elf_Ehdr *elf_get_header(void *elf_image) {
+ return (Elf_Ehdr*)elf_image;
}
/**
* elf_get_pht - Returns a pointer to the first entry in the PHT.
* @elf_image: pointer to the ELF file image in memory
*/
-static inline Elf32_Phdr *elf_get_pht(void *elf_image) {
- Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+static inline Elf_Phdr *elf_get_pht(void *elf_image) {
+ Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
- return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
+ return (Elf_Phdr*)((Elf_Off)elf_hdr + elf_hdr->e_phoff);
}
//
@@ -28,11 +29,11 @@ static inline Elf32_Phdr *elf_get_pht(void *elf_image) {
* @elf_image: pointer to the ELF file image in memory
* @index: the index of the PHT entry to look for
*/
-static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) {
- Elf32_Phdr *elf_pht = elf_get_pht(elf_image);
- Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+static inline Elf_Phdr *elf_get_ph(void *elf_image, int index) {
+ Elf_Phdr *elf_pht = elf_get_pht(elf_image);
+ Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
- return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
+ return (Elf_Phdr*)((Elf_Off)elf_pht + index * elf_hdr->e_phentsize);
}
/**
diff --git a/com32/lib/sys/module/i386/common.h b/com32/lib/sys/module/i386/common.h
new file mode 100644
index 00000000..6259df51
--- /dev/null
+++ b/com32/lib/sys/module/i386/common.h
@@ -0,0 +1,65 @@
+/*
+ * common.h - Common internal operations performed by the module subsystem
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdio.h>
+
+#include <sys/module.h>
+#include <linux/list.h>
+
+#include "elfutils.h"
+
+
+// Performs an operation and jumps to a given label if an error occurs
+#define CHECKED(res, expr, error) \
+ do { \
+ (res) = (expr); \
+ if ((res) < 0) \
+ goto error; \
+ } while (0)
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+//#define ELF_DEBUG
+
+#ifdef ELF_DEBUG
+#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args)
+#else
+#define DBG_PRINT(fmt, args...) // Expand to nothing
+#endif
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_symbols(struct elf_module *module);
+#endif //ELF_DEBUG
+
+
+/*
+ * Image files manipulation routines
+ */
+
+extern int image_load(struct elf_module *module);
+extern int image_unload(struct elf_module *module);
+extern int image_read(void *buff, size_t size, struct elf_module *module);
+extern int image_skip(size_t size, struct elf_module *module);
+extern int image_seek(Elf32_Off offset, struct elf_module *module);
+
+extern struct module_dep *module_dep_alloc(struct elf_module *module);
+
+extern int check_header_common(Elf32_Ehdr *elf_hdr);
+
+extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
+extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
+
+extern int check_symbols(struct elf_module *module);
+
+
+#endif /* COMMON_H_ */
diff --git a/com32/lib/sys/module/i386/elf_module.c b/com32/lib/sys/module/i386/elf_module.c
new file mode 100644
index 00000000..f4a8618a
--- /dev/null
+++ b/com32/lib/sys/module/i386/elf_module.c
@@ -0,0 +1,599 @@
+/*
+ * elf_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+#include <core.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+#include <sys/exec.h>
+
+#include "elfutils.h"
+#include "../common.h"
+
+static int check_header(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_type != MODULE_ELF_TYPE) {
+ DBG_PRINT("The ELF file must be a shared object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_phoff == 0x00000000) {
+ DBG_PRINT("PHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ char *pht = NULL;
+ Elf32_Phdr *cr_pht;
+
+ Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
+ Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr
+ Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+ Elf32_Addr min_alloc, max_alloc; // Min. and max. aligned allocables
+
+ Elf32_Addr dyn_addr = 0x00000000;
+
+ // Get to the PHT
+ image_seek(elf_hdr->e_phoff, module);
+
+ // Load the PHT
+ pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+ image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+ // Compute the memory needings of the module
+ for (i=0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ switch (cr_pht->p_type) {
+ case PT_LOAD:
+ if (i == 0) {
+ min_addr = cr_pht->p_vaddr;
+ } else {
+ min_addr = MIN(min_addr, cr_pht->p_vaddr);
+ }
+
+ max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
+ max_align = MAX(max_align, cr_pht->p_align);
+ break;
+ case PT_DYNAMIC:
+ dyn_addr = cr_pht->p_vaddr;
+ break;
+ default:
+ // Unsupported - ignore
+ break;
+ }
+ }
+
+ if (max_addr - min_addr == 0) {
+ // No loadable segments
+ DBG_PRINT("No loadable segments found\n");
+ goto out;
+ }
+
+ if (dyn_addr == 0) {
+ DBG_PRINT("No dynamic information segment found\n");
+ goto out;
+ }
+
+ // The minimum address that should be allocated
+ min_alloc = min_addr - (min_addr % max_align);
+
+ // The maximum address that should be allocated
+ max_alloc = max_addr - (max_addr % max_align);
+ if (max_addr % max_align > 0)
+ max_alloc += max_align;
+
+
+ if (elf_malloc(&module->module_addr,
+ max_align,
+ max_alloc-min_alloc) != 0) {
+
+ DBG_PRINT("Could not allocate segments\n");
+ goto out;
+ }
+
+ module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
+ module->module_size = max_alloc - min_alloc;
+
+ // Zero-initialize the memory
+ memset(module->module_addr, 0, module->module_size);
+
+ for (i = 0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ if (cr_pht->p_type == PT_LOAD) {
+ // Copy the segment at its destination
+ if (cr_pht->p_offset < module->u.l._cr_offset) {
+ // The segment contains data before the current offset
+ // It can be discarded without worry - it would contain only
+ // headers
+ Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+ if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ } else {
+ if (image_seek(cr_pht->p_offset, module) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+ cr_pht->p_filesz, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ }
+
+ /*
+ DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+ cr_pht->p_filesz,
+ cr_pht->p_vaddr,
+ (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+ */
+ }
+ }
+
+ // Setup dynamic segment location
+ module->dyn_table = module_get_absolute(dyn_addr, module);
+
+ /*
+ DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+ max_align);
+ DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+ */
+
+out:
+ // Free up allocated memory
+ if (pht != NULL)
+ free(pht);
+
+ return res;
+}
+
+static int prepare_dynlinking(struct elf_module *module) {
+ Elf32_Dyn *dyn_entry = module->dyn_table;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch (dyn_entry->d_tag) {
+ case DT_NEEDED:
+ /*
+ * It's unlikely there'll be more than
+ * MAX_NR_DEPS DT_NEEDED entries but if there
+ * are then inform the user that we ran out of
+ * space.
+ */
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
+ else {
+ printf("Too many dependencies!\n");
+ return -1;
+ }
+ break;
+ case DT_HASH:
+ module->hash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_GNU_HASH:
+ module->ghash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRTAB:
+ module->str_table =
+ (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_SYMTAB:
+ module->sym_table =
+ module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRSZ:
+ module->strtable_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_SYMENT:
+ module->syment_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTGOT: // The first entry in the GOT
+ module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ // Now compute the number of symbols in the symbol table
+ if (module->ghash_table != NULL) {
+ module->symtable_size = module->ghash_table[1];
+ } else {
+ module->symtable_size = module->hash_table[1];
+ }
+
+ return 0;
+}
+
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
+
+static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
+ Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
+
+ // The symbol reference index
+ Elf32_Word sym = ELF32_R_SYM(rel->r_info);
+ unsigned char type = ELF32_R_TYPE(rel->r_info);
+
+ // The symbol definition (if applicable)
+ Elf32_Sym *sym_def = NULL;
+ struct elf_module *sym_module = NULL;
+ Elf32_Addr sym_addr = 0x0;
+
+ if (sym > 0) {
+ // Find out details about the symbol
+
+ // The symbol reference
+ Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
+
+ // The symbol definition
+ sym_def =
+ global_find_symbol(module->str_table + sym_ref->st_name,
+ &sym_module);
+
+ if (sym_def == NULL) {
+ DBG_PRINT("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+
+ if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
+ }
+
+ // Compute the absolute symbol virtual address
+ sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module);
+
+ if (sym_module != module) {
+ // Create a dependency
+ enforce_dependency(sym_module, module);
+ }
+ }
+
+ switch (type) {
+ case R_386_NONE:
+ // Do nothing
+ break;
+ case R_386_32:
+ *dest += sym_addr;
+ break;
+ case R_386_PC32:
+ *dest += sym_addr - (Elf32_Addr)dest;
+ break;
+ case R_386_COPY:
+ if (sym_addr > 0) {
+ memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+ }
+ break;
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ // Maybe TODO: Keep track of the GOT entries allocations
+ *dest = sym_addr;
+ break;
+ case R_386_RELATIVE:
+ *dest += module->base_addr;
+ break;
+ default:
+ DBG_PRINT("Relocation type %d not supported\n", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int resolve_symbols(struct elf_module *module) {
+ Elf32_Dyn *dyn_entry = module->dyn_table;
+ unsigned int i;
+ int res;
+
+ Elf32_Word plt_rel_size = 0;
+ char *plt_rel = NULL;
+
+ char *rel = NULL;
+ Elf32_Word rel_size = 0;
+ Elf32_Word rel_entry = 0;
+
+ // The current relocation
+ Elf32_Rel *crt_rel;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch(dyn_entry->d_tag) {
+
+ // PLT relocation information
+ case DT_PLTRELSZ:
+ plt_rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ if (dyn_entry->d_un.d_val != DT_REL) {
+ DBG_PRINT("Unsupported PLT relocation\n");
+ return -1;
+ }
+ case DT_JMPREL:
+ plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+
+ // Standard relocation information
+ case DT_REL:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELSZ:
+ rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELENT:
+ rel_entry = dyn_entry->d_un.d_val;
+ break;
+
+ // Module initialization and termination
+ case DT_INIT:
+ // TODO Implement initialization functions
+ break;
+ case DT_FINI:
+ // TODO Implement finalization functions
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ if (rel_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rel_size/rel_entry; i++) {
+ crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+
+ }
+
+ if (plt_rel_size > 0) {
+ // TODO: Permit this lazily
+ // Process PLT relocations
+ for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
+ crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *ctors_start, *ctors_end;
+ Elf32_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
+
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
+ }
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
+ }
+
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
+ }
+
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
+
+ return 0;
+}
+
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf32_Sym *main_sym;
+ Elf32_Ehdr elf_hdr;
+ module_ctor_t *ctor;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module %s is already loaded.\n", module->name);
+ return EEXIST;
+ }
+
+ // Get a mapping/copy of the ELF file in memory
+ res = image_load(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ // The module is a fully featured dynamic library
+ module->shallow = 0;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+ //printf("check... 1\n");
+
+ //print_elf_ehdr(&elf_hdr);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header(&elf_hdr), error);
+ //printf("check... 2\n");
+
+ // Load the segments in the memory
+ CHECKED(res, load_segments(module, &elf_hdr), error);
+ //printf("bleah... 3\n");
+ // Obtain dynamic linking information
+ CHECKED(res, prepare_dynlinking(module), error);
+ //printf("check... 4\n");
+
+ /* Find modules we need to load as dependencies */
+ if (module->str_table) {
+ int i;
+
+ /*
+ * Note that we have to load the dependencies in
+ * reverse order.
+ */
+ for (i = module->nr_needed - 1; i >= 0; i--) {
+ char *dep, *p;
+ char *argv[2] = { NULL, NULL };
+
+ dep = module->str_table + module->needed[i];
+
+ /* strip everything but the last component */
+ if (!strlen(dep))
+ continue;
+
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
+
+ argv[0] = p;
+ spawn_load(p, 1, argv);
+ }
+ }
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+ //printf("check... 5\n");
+
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
+ //printf("check... 6\n");
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // Perform the relocations
+ resolve_symbols(module);
+
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
+ //dprintf("module->symtable_size = %d\n", module->symtable_size);
+
+ //print_elf_symbols(module);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ /*
+ DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n",
+ module->name,
+ (module->main_func == NULL) ? NULL : *(module->main_func),
+ (module->init_func == NULL) ? NULL : *(module->init_func),
+ (module->exit_func == NULL) ? NULL : *(module->exit_func));
+ */
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
+ return 0;
+
+error:
+ // Remove the module from the module list (if applicable)
+ list_del_init(&module->list);
+
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+ module->module_addr = NULL;
+ }
+
+ image_unload(module);
+
+ // Clear the execution part of the module buffer
+ memset(&module->u, 0, sizeof module->u);
+
+ return res;
+}
+
diff --git a/com32/lib/sys/module/i386/shallow_module.c b/com32/lib/sys/module/i386/shallow_module.c
new file mode 100644
index 00000000..fbcf781b
--- /dev/null
+++ b/com32/lib/sys/module/i386/shallow_module.c
@@ -0,0 +1,161 @@
+/*
+ * shallow_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <string.h>
+#include <sys/module.h>
+
+#include "common.h"
+#include "elfutils.h"
+
+
+static int check_header_shallow(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_shoff == 0x00000000) {
+ DBG_PRINT("SHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *sht = NULL;
+ void *buffer = NULL;
+ Elf32_Shdr *crt_sht;
+ Elf32_Off buff_offset;
+
+ Elf32_Off min_offset = 0xFFFFFFFF;
+ Elf32_Off max_offset = 0x00000000;
+ Elf32_Word max_align = 0x1;
+
+ Elf32_Off sym_offset = 0xFFFFFFFF;
+ Elf32_Off str_offset = 0xFFFFFFFF;
+
+
+ char *sh_strtable;
+
+ // We buffer the data up to the SHT
+ buff_offset = module->u.l._cr_offset;
+
+ buffer = malloc(elf_hdr->e_shoff - buff_offset);
+ // Get to the SHT
+ image_read(buffer, elf_hdr->e_shoff - buff_offset, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Get the string table of the section names
+ crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize);
+ sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset));
+
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize);
+
+ if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the symbol table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ sym_offset = crt_sht->sh_offset;
+
+ module->syment_size = crt_sht->sh_entsize;
+ module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize;
+ }
+ if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the string table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ str_offset = crt_sht->sh_offset;
+
+ module->strtable_size = crt_sht->sh_size;
+ }
+ }
+
+ if (elf_malloc(&module->module_addr, max_align,
+ max_offset - min_offset) != 0) {
+ DBG_PRINT("Could not allocate sections\n");
+ goto out;
+ }
+
+ // Copy the data
+ image_seek(min_offset, module);
+ image_read(module->module_addr, max_offset - min_offset, module);
+
+ // Setup module information
+ module->module_size = max_offset - min_offset;
+ module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
+ module->sym_table = module->module_addr + (sym_offset - min_offset);
+
+out:
+ // Release the SHT
+ if (sht != NULL)
+ free(sht);
+
+ // Release the buffer
+ if (buffer != NULL)
+ free(buffer);
+
+ return res;
+}
+
+
+int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr) {
+ int res;
+ Elf32_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module already loaded.\n");
+ return -1;
+ }
+
+ res = image_load(module);
+
+ if (res < 0)
+ return res;
+
+ module->shallow = 1;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header_shallow(&elf_hdr), error);
+
+ CHECKED(res, load_shallow_sections(module, &elf_hdr), error);
+ module->base_addr = base_addr;
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name);
+
+ return 0;
+
+error:
+ image_unload(module);
+
+ return res;
+}
diff --git a/com32/lib/sys/module/x86_64/common.h b/com32/lib/sys/module/x86_64/common.h
new file mode 100644
index 00000000..e7946f91
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/common.h
@@ -0,0 +1,64 @@
+/*
+ * common.h - Common internal operations performed by the module subsystem
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdio.h>
+
+#include <sys/module.h>
+#include <linux/list.h>
+
+#include "elfutils.h"
+
+// Performs an operation and jumps to a given label if an error occurs
+#define CHECKED(res, expr, error) \
+ do { \
+ (res) = (expr); \
+ if ((res) < 0) \
+ goto error; \
+ } while (0)
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+//#define ELF_DEBUG
+
+#ifdef ELF_DEBUG
+#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args)
+#else
+#define DBG_PRINT(fmt, args...) // Expand to nothing
+#endif
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+extern void print_elf_ehdr(Elf64_Ehdr *ehdr);
+extern void print_elf_symbols(struct elf_module *module);
+#endif //ELF_DEBUG
+
+
+/*
+ * Image files manipulation routines
+ */
+
+extern int image_load(struct elf_module *module);
+extern int image_unload(struct elf_module *module);
+extern int image_read(void *buff, size_t size, struct elf_module *module);
+extern int image_skip(size_t size, struct elf_module *module);
+extern int image_seek(Elf64_Off offset, struct elf_module *module);
+
+extern struct module_dep *module_dep_alloc(struct elf_module *module);
+
+extern int check_header_common(Elf64_Ehdr *elf_hdr);
+
+extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
+extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
+
+extern int check_symbols(struct elf_module *module);
+
+
+#endif /* COMMON_H_ */
diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c
new file mode 100644
index 00000000..3c164996
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/elf_module.c
@@ -0,0 +1,631 @@
+/*
+ * elf_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+#include <core.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+#include <sys/exec.h>
+
+#include "elfutils.h"
+#include "../common.h"
+
+static int check_header(Elf64_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_type != MODULE_ELF_TYPE) {
+ DBG_PRINT("The ELF file must be a shared object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_phoff == 0x00000000) {
+ DBG_PRINT("PHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+static int load_segments(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ char *pht = NULL;
+ Elf64_Phdr *cr_pht;
+
+ Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr
+ Elf64_Addr max_addr = 0x0000000000000000; // Max. ELF vaddr
+ Elf64_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+ Elf64_Addr min_alloc, max_alloc; // Min. and max. aligned allocables
+
+ Elf64_Addr dyn_addr = 0x0000000000000000;
+
+ // Get to the PHT
+ image_seek(elf_hdr->e_phoff, module);
+
+ // Load the PHT
+ pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+ image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+ // Compute the memory needings of the module
+ for (i=0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ switch (cr_pht->p_type) {
+ case PT_LOAD:
+ if (i == 0) {
+ min_addr = cr_pht->p_vaddr;
+ } else {
+ min_addr = MIN(min_addr, cr_pht->p_vaddr);
+ }
+
+ max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
+ max_align = MAX(max_align, cr_pht->p_align);
+ break;
+ case PT_DYNAMIC:
+ dyn_addr = cr_pht->p_vaddr;
+ break;
+ default:
+ // Unsupported - ignore
+ break;
+ }
+ }
+
+ if (max_addr - min_addr == 0) {
+ // No loadable segments
+ DBG_PRINT("No loadable segments found\n");
+ goto out;
+ }
+
+ if (dyn_addr == 0) {
+ DBG_PRINT("No dynamic information segment found\n");
+ goto out;
+ }
+
+ // The minimum address that should be allocated
+ min_alloc = min_addr - (min_addr % max_align);
+
+ // The maximum address that should be allocated
+ max_alloc = max_addr - (max_addr % max_align);
+ if (max_addr % max_align > 0)
+ max_alloc += max_align;
+
+
+ if (elf_malloc(&module->module_addr,
+ max_align,
+ max_alloc-min_alloc) != 0) {
+
+ DBG_PRINT("Could not allocate segments\n");
+ goto out;
+ }
+
+ module->base_addr = (Elf64_Addr)(module->module_addr) - min_alloc;
+ module->module_size = max_alloc - min_alloc;
+
+ // Zero-initialize the memory
+ memset(module->module_addr, 0, module->module_size);
+
+ for (i = 0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ if (cr_pht->p_type == PT_LOAD) {
+ // Copy the segment at its destination
+ if (cr_pht->p_offset < module->u.l._cr_offset) {
+ // The segment contains data before the current offset
+ // It can be discarded without worry - it would contain only
+ // headers
+ Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+ if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ } else {
+ if (image_seek(cr_pht->p_offset, module) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+ cr_pht->p_filesz, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ }
+
+ /*
+ DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+ cr_pht->p_filesz,
+ cr_pht->p_vaddr,
+ (Elf64_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+ */
+ }
+ }
+
+ // Setup dynamic segment location
+ module->dyn_table = module_get_absolute(dyn_addr, module);
+
+ /*
+ DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+ max_align);
+ DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+ */
+
+out:
+ // Free up allocated memory
+ if (pht != NULL)
+ free(pht);
+
+ return res;
+}
+
+static int prepare_dynlinking(struct elf_module *module) {
+ Elf64_Dyn *dyn_entry = module->dyn_table;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch (dyn_entry->d_tag) {
+ case DT_NEEDED:
+ /*
+ * It's unlikely there'll be more than
+ * MAX_NR_DEPS DT_NEEDED entries but if there
+ * are then inform the user that we ran out of
+ * space.
+ */
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
+ else {
+ printf("Too many dependencies!\n");
+ return -1;
+ }
+ break;
+ case DT_HASH:
+ module->hash_table =
+ (Elf64_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_GNU_HASH:
+ module->ghash_table =
+ (Elf64_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRTAB:
+ module->str_table =
+ (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_SYMTAB:
+ module->sym_table =
+ module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRSZ:
+ module->strtable_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_SYMENT:
+ module->syment_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTGOT: // The first entry in the GOT
+ module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ // Now compute the number of symbols in the symbol table
+ if (module->ghash_table != NULL) {
+ module->symtable_size = module->ghash_table[1];
+ } else {
+ module->symtable_size = module->hash_table[1];
+ }
+
+ return 0;
+}
+
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
+
+static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
+ Elf64_Xword *dest = module_get_absolute(rel->r_offset, module);
+
+ // The symbol reference index
+ Elf64_Word sym = ELF64_R_SYM(rel->r_info);
+ unsigned char type = ELF64_R_TYPE(rel->r_info);
+
+ // The symbol definition (if applicable)
+ Elf64_Sym *sym_def = NULL;
+ struct elf_module *sym_module = NULL;
+ Elf64_Addr sym_addr = 0x0;
+
+ if (sym > 0) {
+ // Find out details about the symbol
+
+ // The symbol reference
+ Elf64_Sym *sym_ref = symbol_get_entry(module, sym);
+
+ // The symbol definition
+ sym_def =
+ global_find_symbol(module->str_table + sym_ref->st_name,
+ &sym_module);
+
+ if (sym_def == NULL) {
+ DBG_PRINT("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+
+ if (ELF64_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
+ }
+
+ // Compute the absolute symbol virtual address
+ sym_addr = (Elf64_Addr)module_get_absolute(sym_def->st_value, sym_module);
+
+ if (sym_module != module) {
+ // Create a dependency
+ enforce_dependency(sym_module, module);
+ }
+ }
+
+ switch (type) {
+ case R_X86_64_NONE:
+ // Do nothing
+ break;
+ case R_X86_64_64:
+ *dest += sym_addr;
+ break;
+ case R_X86_64_PC32:
+ *dest += sym_addr - (Elf32_Addr)dest;
+ break;
+ case R_X86_64_COPY:
+ if (sym_addr > 0) {
+ memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+ }
+ break;
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ //Maybe TODO: Keep track of the GOT entries allocations
+ *dest = sym_addr;
+ break;
+ case R_X86_64_RELATIVE:
+ *dest += module->base_addr;
+ break;
+ default:
+ DBG_PRINT("Relocation type %d not supported\n", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int resolve_symbols(struct elf_module *module) {
+ Elf64_Dyn *dyn_entry = module->dyn_table;
+ unsigned int i;
+ int res;
+
+ Elf64_Word plt_rel_size = 0;
+ void *plt_rel = NULL;
+
+ void *rel = NULL;
+ Elf64_Word rel_size = 0;
+ Elf64_Word rel_entry = 0;
+ Elf64_Xword rela_size = 0;
+ Elf64_Xword rela_entry = 0;
+ Elf64_Xword sym_ent = 0;
+
+ // The current relocation
+ Elf64_Rel *crt_rel;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch(dyn_entry->d_tag) {
+
+ // PLT relocation information
+ case DT_PLTRELSZ:
+ plt_rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ if (dyn_entry->d_un.d_val != DT_REL && dyn_entry->d_un.d_val != DT_RELA) {
+ DBG_PRINT("Unsupported PLT relocation\n");
+ return -1;
+ }
+ //break;
+ case DT_JMPREL:
+ plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+
+ // Standard relocation information
+ case DT_REL:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELA:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELSZ:
+ rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELASZ:
+ rela_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELENT:
+ rel_entry = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELAENT:
+ rela_entry = dyn_entry->d_un.d_val;
+ break;
+ /* FIXME: We may need to rely upon SYMENT if DT_RELAENT is missing in the object file */
+ case DT_SYMENT:
+ sym_ent = dyn_entry->d_un.d_val;
+ break;
+
+ // Module initialization and termination
+ case DT_INIT:
+ // TODO Implement initialization functions
+ break;
+ case DT_FINI:
+ // TODO Implement finalization functions
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ if (rel_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rel_size/rel_entry; i++) {
+ crt_rel = (Elf64_Rel*)(rel + i*rel_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+
+ }
+
+ if (rela_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rela_size/rela_entry; i++) {
+ crt_rel = (Elf64_Rel*)(rel + i*rela_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+ }
+ if (plt_rel_size > 0) {
+ // TODO: Permit this lazily
+ // Process PLT relocations
+ /* some modules do not have DT_SYMENT, set it sym_ent in such cases */
+ if (!rela_entry) rela_entry = sym_ent;
+ //for (i = 0; i < plt_rel_size/sizeof(Elf64_Rel); i++) {
+ for (i = 0; i < plt_rel_size/rela_entry; i++) {
+ //crt_rel = (Elf64_Rel*)(plt_rel + i*sizeof(Elf64_Rel));
+ crt_rel = (Elf64_Rel*)(plt_rel + i*rela_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+static int extract_operations(struct elf_module *module) {
+ Elf64_Sym *ctors_start, *ctors_end;
+ Elf64_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
+
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
+ }
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
+ }
+
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
+ }
+
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
+
+ return 0;
+}
+
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf64_Sym *main_sym;
+ Elf64_Ehdr elf_hdr;
+ module_ctor_t *ctor;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module %s is already loaded.\n", module->name);
+ return EEXIST;
+ }
+
+ // Get a mapping/copy of the ELF file in memory
+ res = image_load(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ // The module is a fully featured dynamic library
+ module->shallow = 0;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf64_Ehdr), module), error);
+ //printf("check... 1\n");
+
+ //print_elf_ehdr(&elf_hdr);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header(&elf_hdr), error);
+ //printf("check... 2\n");
+
+ // Load the segments in the memory
+ CHECKED(res, load_segments(module, &elf_hdr), error);
+ //printf("bleah... 3\n");
+ // Obtain dynamic linking information
+ CHECKED(res, prepare_dynlinking(module), error);
+ //printf("check... 4\n");
+
+ /* Find modules we need to load as dependencies */
+ if (module->str_table) {
+ int i;
+
+ /*
+ * Note that we have to load the dependencies in
+ * reverse order.
+ */
+ for (i = module->nr_needed - 1; i >= 0; i--) {
+ char *dep, *p;
+ char *argv[2] = { NULL, NULL };
+
+ dep = module->str_table + module->needed[i];
+
+ /* strip everything but the last component */
+ if (!strlen(dep))
+ continue;
+
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
+
+ argv[0] = p;
+ spawn_load(p, 1, argv);
+ }
+ }
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+ //printf("check... 5\n");
+
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
+ //printf("check... 6\n");
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // Perform the relocations
+ resolve_symbols(module);
+
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
+ //dprintf("module->symtable_size = %d\n", module->symtable_size);
+
+ //print_elf_symbols(module);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ /*
+ DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n",
+ module->name,
+ (module->main_func == NULL) ? NULL : *(module->main_func),
+ (module->init_func == NULL) ? NULL : *(module->init_func),
+ (module->exit_func == NULL) ? NULL : *(module->exit_func));
+ */
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
+ return 0;
+
+error:
+ // Remove the module from the module list (if applicable)
+ list_del_init(&module->list);
+
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+ module->module_addr = NULL;
+ }
+
+ image_unload(module);
+
+ // Clear the execution part of the module buffer
+ memset(&module->u, 0, sizeof module->u);
+
+ return res;
+}
+
diff --git a/com32/lib/sys/module/x86_64/elfutils.h b/com32/lib/sys/module/x86_64/elfutils.h
new file mode 100644
index 00000000..dbfc7608
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/elfutils.h
@@ -0,0 +1,64 @@
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#include <elf.h>
+#include <stdlib.h>
+
+/**
+ * elf_get_header - Returns a pointer to the ELF header structure.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf64_Ehdr *elf_get_header(void *elf_image) {
+ return (Elf64_Ehdr*)elf_image;
+}
+
+/**
+ * elf_get_pht - Returns a pointer to the first entry in the PHT.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf64_Phdr *elf_get_pht(void *elf_image) {
+ Elf64_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf64_Phdr*)((Elf64_Off)elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+static inline Elf64_Phdr *elf_get_ph(void *elf_image, int index) {
+ Elf64_Phdr *elf_pht = elf_get_pht(elf_image);
+ Elf64_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf64_Phdr*)((Elf64_Off)elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(void *memptr);
+
+#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/x86_64/shallow_module.c b/com32/lib/sys/module/x86_64/shallow_module.c
new file mode 100644
index 00000000..b7248150
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/shallow_module.c
@@ -0,0 +1,161 @@
+/*
+ * shallow_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <string.h>
+#include <sys/module.h>
+
+#include "common.h"
+#include "elfutils.h"
+
+
+static int check_header_shallow(Elf64_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_shoff == 0x00000000) {
+ DBG_PRINT("SHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int load_shallow_sections(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *sht = NULL;
+ void *buffer = NULL;
+ Elf64_Shdr *crt_sht;
+ Elf64_Off buff_offset;
+
+ Elf64_Off min_offset = 0xFFFFFFFFFFFFFFFF;
+ Elf64_Off max_offset = 0x0000000000000000;
+ Elf64_Word max_align = 0x1;
+
+ Elf64_Off sym_offset = 0xFFFFFFFFFFFFFFFF;
+ Elf64_Off str_offset = 0xFFFFFFFFFFFFFFFF;
+
+
+ char *sh_strtable;
+
+ // We buffer the data up to the SHT
+ buff_offset = module->u.l._cr_offset;
+
+ buffer = malloc(elf_hdr->e_shoff - buff_offset);
+ // Get to the SHT
+ image_read(buffer, elf_hdr->e_shoff - buff_offset, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Get the string table of the section names
+ crt_sht = (Elf64_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize);
+ sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset));
+
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ crt_sht = (Elf64_Shdr*)(sht + i*elf_hdr->e_shentsize);
+
+ if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the symbol table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ sym_offset = crt_sht->sh_offset;
+
+ module->syment_size = crt_sht->sh_entsize;
+ module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize;
+ }
+ if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the string table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ str_offset = crt_sht->sh_offset;
+
+ module->strtable_size = crt_sht->sh_size;
+ }
+ }
+
+ if (elf_malloc(&module->module_addr, max_align,
+ max_offset - min_offset) != 0) {
+ DBG_PRINT("Could not allocate sections\n");
+ goto out;
+ }
+
+ // Copy the data
+ image_seek(min_offset, module);
+ image_read(module->module_addr, max_offset - min_offset, module);
+
+ // Setup module information
+ module->module_size = max_offset - min_offset;
+ module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
+ module->sym_table = module->module_addr + (sym_offset - min_offset);
+
+out:
+ // Release the SHT
+ if (sht != NULL)
+ free(sht);
+
+ // Release the buffer
+ if (buffer != NULL)
+ free(buffer);
+
+ return res;
+}
+
+
+int module_load_shallow(struct elf_module *module, Elf64_Addr base_addr) {
+ int res;
+ Elf64_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module already loaded.\n");
+ return -1;
+ }
+
+ res = image_load(module);
+
+ if (res < 0)
+ return res;
+
+ module->shallow = 1;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf64_Ehdr), module), error);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header_shallow(&elf_hdr), error);
+
+ CHECKED(res, load_shallow_sections(module, &elf_hdr), error);
+ module->base_addr = base_addr;
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name);
+
+ return 0;
+
+error:
+ image_unload(module);
+
+ return res;
+}
diff --git a/com32/lib/sys/vesa/efi/background.c b/com32/lib/sys/vesa/efi/background.c
new file mode 100644
index 00000000..93577461
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/background.c
@@ -0,0 +1,456 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <png.h>
+#include <tinyjpeg.h>
+#include <com32.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <minmax.h>
+#include <stdbool.h>
+#include <ilog2.h>
+#include <syslinux/loadfile.h>
+#include "vesa.h"
+#include "video.h"
+
+/*** FIX: This really should be alpha-blended with color index 0 ***/
+
+/* For best performance, "start" should be a multiple of 4, to assure
+ aligned dwords. */
+static void draw_background_line(int line, int start, int npixels)
+{
+ uint32_t *bgptr = &__vesacon_background[line*__vesa_info.mi.h_res+start];
+ unsigned int bytes_per_pixel = __vesacon_bytes_per_pixel;
+ size_t fbptr = line * __vesa_info.mi.logical_scan + start*bytes_per_pixel;
+
+ __vesacon_copy_to_screen(fbptr, bgptr, npixels);
+}
+
+/* This draws the border, then redraws the text area */
+static void draw_background(void)
+{
+ int i;
+ const int bottom_border = VIDEO_BORDER +
+ (TEXT_PIXEL_ROWS % __vesacon_font_height);
+ const int right_border = VIDEO_BORDER + (TEXT_PIXEL_COLS % FONT_WIDTH);
+
+ for (i = 0; i < VIDEO_BORDER; i++)
+ draw_background_line(i, 0, __vesa_info.mi.h_res);
+
+ for (i = VIDEO_BORDER; i < __vesa_info.mi.v_res - bottom_border; i++) {
+ draw_background_line(i, 0, VIDEO_BORDER);
+ draw_background_line(i, __vesa_info.mi.h_res - right_border,
+ right_border);
+ }
+
+ for (i = __vesa_info.mi.v_res - bottom_border;
+ i < __vesa_info.mi.v_res; i++)
+ draw_background_line(i, 0, __vesa_info.mi.h_res);
+
+ __vesacon_redraw_text();
+}
+
+/*
+ * Tile an image in the UL corner across the entire screen
+ */
+static void tile_image(int width, int height)
+{
+ int xsize = __vesa_info.mi.h_res;
+ int ysize = __vesa_info.mi.v_res;
+ int x, y, yr;
+ int xl, yl;
+ uint32_t *sp, *dp, *drp, *dtp;
+
+ drp = __vesacon_background;
+ for (y = 0 ; y < ysize ; y += height) {
+ yl = min(height, ysize-y);
+ dtp = drp;
+ for (x = 0 ; x < xsize ; x += width) {
+ xl = min(width, xsize-x);
+ if (x || y) {
+ sp = __vesacon_background;
+ dp = dtp;
+ for (yr = 0 ; yr < yl ; yr++) {
+ memcpy(dp, sp, xl*sizeof(uint32_t));
+ dp += xsize;
+ sp += xsize;
+ }
+ }
+ dtp += xl;
+ }
+ drp += xsize*height;
+ }
+}
+
+static int read_png_file(FILE * fp)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+#if 0
+ png_color_16p image_background;
+ static const png_color_16 my_background = { 0, 0, 0, 0, 0 };
+#endif
+ png_bytep row_pointers[__vesa_info.mi.v_res], rp;
+ int i;
+ int rv = -1;
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ info_ptr = png_create_info_struct(png_ptr);
+
+ if (!png_ptr || !info_ptr || setjmp(png_jmpbuf(png_ptr)))
+ goto err;
+
+ png_init_io(png_ptr, fp);
+ png_set_sig_bytes(png_ptr, 8);
+
+ png_set_user_limits(png_ptr, __vesa_info.mi.h_res, __vesa_info.mi.v_res);
+
+ png_read_info(png_ptr, info_ptr);
+
+ /* Set the appropriate set of transformations. We need to end up
+ with 32-bit BGRA format, no more, no less. */
+
+ /* Expand to RGB first... */
+ if (info_ptr->color_type & PNG_COLOR_MASK_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+ else if (!(info_ptr->color_type & PNG_COLOR_MASK_COLOR))
+ png_set_gray_to_rgb(png_ptr);
+
+ /* Add alpha channel, if need be */
+ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA)) {
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png_ptr);
+ else
+ png_set_add_alpha(png_ptr, ~0, PNG_FILLER_AFTER);
+ }
+
+ /* Adjust the byte order, if necessary */
+ png_set_bgr(png_ptr);
+
+ /* Make sure we end up with 8-bit data */
+ if (info_ptr->bit_depth == 16)
+ png_set_strip_16(png_ptr);
+ else if (info_ptr->bit_depth < 8)
+ png_set_packing(png_ptr);
+
+#if 0
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+#endif
+
+ /* Whew! Now we should get the stuff we want... */
+ rp = (png_bytep)__vesacon_background;
+ for (i = 0; i < (int)info_ptr->height; i++) {
+ row_pointers[i] = rp;
+ rp += __vesa_info.mi.h_res << 2;
+ }
+
+ png_read_image(png_ptr, row_pointers);
+
+ tile_image(info_ptr->width, info_ptr->height);
+
+ rv = 0;
+
+err:
+ if (png_ptr)
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+ return rv;
+}
+
+static int jpeg_sig_cmp(uint8_t * bytes, int len)
+{
+ (void)len;
+
+ return (bytes[0] == 0xff && bytes[1] == 0xd8) ? 0 : -1;
+}
+
+static int read_jpeg_file(FILE * fp, uint8_t * header, int len)
+{
+ struct jdec_private *jdec = NULL;
+ void *jpeg_file = NULL;
+ size_t length_of_file;
+ unsigned int width, height;
+ int rv = -1;
+ unsigned char *components[1];
+ unsigned int bytes_per_row[1];
+
+ rv = floadfile(fp, &jpeg_file, &length_of_file, header, len);
+ fclose(fp);
+ if (rv)
+ goto err;
+
+ jdec = tinyjpeg_init();
+ if (!jdec)
+ goto err;
+
+ if (tinyjpeg_parse_header(jdec, jpeg_file, length_of_file) < 0)
+ goto err;
+
+ tinyjpeg_get_size(jdec, &width, &height);
+ if (width > __vesa_info.mi.h_res || height > __vesa_info.mi.v_res)
+ goto err;
+
+ components[0] = (void *)__vesacon_background;
+ tinyjpeg_set_components(jdec, components, 1);
+ bytes_per_row[0] = __vesa_info.mi.h_res << 2;
+ tinyjpeg_set_bytes_per_row(jdec, bytes_per_row, 1);
+
+ tinyjpeg_decode(jdec, TINYJPEG_FMT_BGRA32);
+ tile_image(width, height);
+
+ rv = 0;
+
+err:
+ /* Don't use tinyjpeg_free() here, since we didn't allow tinyjpeg
+ to allocate the frame buffer */
+ if (jdec)
+ free(jdec);
+
+ if (jpeg_file)
+ free(jpeg_file);
+
+ return rv;
+}
+
+/* Simple grey Gaussian hole, enough to look interesting */
+int vesacon_default_background(void)
+{
+ int x, y, dx, dy, dy2;
+ int z;
+ unsigned int shft;
+ uint8_t *bgptr = (uint8_t *)__vesacon_background;
+ uint8_t k;
+
+ if (__vesacon_pixel_format == PXF_NONE)
+ return 0; /* Not in graphics mode */
+
+ z = max(__vesa_info.mi.v_res, __vesa_info.mi.h_res) >> 1;
+ z = ((z*z) >> 11) - 1;
+ shft = ilog2(z) + 1;
+
+ for (y = 0, dy = -(__vesa_info.mi.v_res >> 1);
+ y < __vesa_info.mi.v_res; y++, dy++) {
+ dy2 = dy * dy;
+ for (x = 0, dx = -(__vesa_info.mi.h_res >> 1);
+ x < __vesa_info.mi.h_res; x++, dx++) {
+ k = __vesacon_linear_to_srgb[500 + ((dx*dx + dy2) >> shft)];
+ bgptr[0] = k; /* Blue */
+ bgptr[1] = k; /* Green */
+ bgptr[2] = k; /* Red */
+ bgptr += 4; /* Dummy alpha */
+ }
+ }
+
+ draw_background();
+ return 0;
+}
+
+/* Set the background to a single flat color */
+int vesacon_set_background(unsigned int rgb)
+{
+ void *bgptr = __vesacon_background;
+ unsigned int count = __vesa_info.mi.h_res * __vesa_info.mi.v_res;
+
+ if (__vesacon_pixel_format == PXF_NONE)
+ return 0; /* Not in graphics mode */
+
+ asm volatile ("rep; stosl":"+D" (bgptr), "+c"(count)
+ :"a"(rgb)
+ :"memory");
+
+ draw_background();
+ return 0;
+}
+
+struct lss16_header {
+ uint32_t magic;
+ uint16_t xsize;
+ uint16_t ysize;
+};
+
+#define LSS16_MAGIC 0x1413f33d
+
+static inline int lss16_sig_cmp(const void *header, int len)
+{
+ const struct lss16_header *h = header;
+
+ if (len != 8)
+ return 1;
+
+ return !(h->magic == LSS16_MAGIC &&
+ h->xsize <= __vesa_info.mi.h_res &&
+ h->ysize <= __vesa_info.mi.v_res);
+}
+
+static int read_lss16_file(FILE * fp, const void *header, int header_len)
+{
+ const struct lss16_header *h = header;
+ uint32_t colors[16], color;
+ bool has_nybble;
+ uint8_t byte;
+ int count;
+ int nybble, prev;
+ enum state {
+ st_start,
+ st_c0,
+ st_c1,
+ st_c2,
+ } state;
+ int i, x, y;
+ uint32_t *bgptr = __vesacon_background;
+
+ /* Assume the header, 8 bytes, has already been loaded. */
+ if (header_len != 8)
+ return -1;
+
+ for (i = 0; i < 16; i++) {
+ uint8_t rgb[3];
+ if (fread(rgb, 1, 3, fp) != 3)
+ return -1;
+
+ colors[i] = (((rgb[0] & 63) * 255 / 63) << 16) +
+ (((rgb[1] & 63) * 255 / 63) << 8) +
+ ((rgb[2] & 63) * 255 / 63);
+ }
+
+ /* By spec, the state machine is per row */
+ for (y = 0; y < h->ysize; y++) {
+ state = st_start;
+ has_nybble = false;
+ color = colors[prev = 0]; /* By specification */
+ count = 0;
+
+ x = 0;
+ while (x < h->xsize) {
+ if (!has_nybble) {
+ if (fread(&byte, 1, 1, fp) != 1)
+ return -1;
+ nybble = byte & 0xf;
+ has_nybble = true;
+ } else {
+ nybble = byte >> 4;
+ has_nybble = false;
+ }
+
+ switch (state) {
+ case st_start:
+ if (nybble != prev) {
+ *bgptr++ = color = colors[prev = nybble];
+ x++;
+ } else {
+ state = st_c0;
+ }
+ break;
+
+ case st_c0:
+ if (nybble == 0) {
+ state = st_c1;
+ } else {
+ count = nybble;
+ goto do_run;
+ }
+ break;
+
+ case st_c1:
+ count = nybble + 16;
+ state = st_c2;
+ break;
+
+ case st_c2:
+ count += nybble << 4;
+ goto do_run;
+
+do_run:
+ count = min(count, h->xsize - x);
+ x += count;
+ asm volatile ("rep; stosl":"+D" (bgptr),
+ "+c"(count):"a"(color));
+ state = st_start;
+ break;
+ }
+ }
+
+ /* Zero-fill rest of row */
+ i = __vesa_info.mi.h_res - x;
+ asm volatile ("rep; stosl":"+D" (bgptr), "+c"(i):"a"(0):"memory");
+ }
+
+ /* Zero-fill rest of screen */
+ i = (__vesa_info.mi.v_res - y) * __vesa_info.mi.h_res;
+ asm volatile ("rep; stosl":"+D" (bgptr), "+c"(i):"a"(0):"memory");
+
+ return 0;
+}
+
+int vesacon_load_background(const char *filename)
+{
+ FILE *fp = NULL;
+ uint8_t header[8];
+ int rv = 1;
+
+ if (__vesacon_pixel_format == PXF_NONE)
+ return 0; /* Not in graphics mode */
+
+ fp = fopen(filename, "r");
+
+ if (!fp)
+ goto err;
+
+ if (fread(header, 1, 8, fp) != 8)
+ goto err;
+
+ if (!png_sig_cmp(header, 0, 8)) {
+ rv = read_png_file(fp);
+ } else if (!jpeg_sig_cmp(header, 8)) {
+ rv = read_jpeg_file(fp, header, 8);
+ } else if (!lss16_sig_cmp(header, 8)) {
+ rv = read_lss16_file(fp, header, 8);
+ }
+
+ /* This actually displays the stuff */
+ draw_background();
+
+err:
+ if (fp)
+ fclose(fp);
+
+ return rv;
+}
+
+int __vesacon_init_background(void)
+{
+ /* __vesacon_background was cleared by calloc() */
+
+ /* The VESA BIOS has already cleared the screen */
+ return 0;
+}
diff --git a/com32/lib/sys/vesa/efi/cp865_8x16.h b/com32/lib/sys/vesa/efi/cp865_8x16.h
new file mode 100644
index 00000000..9c8a2678
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/cp865_8x16.h
@@ -0,0 +1,262 @@
+static const short cp865_8x16_font_magic = 0x436;
+static const unsigned cp865_8x16_font_mode = 0x0;
+static const int cp865_8x16_font_height = 0x10;
+static const uint8_t cp865_8x16_font_data[] = {
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x36, 0x32, 0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x18, 0x70, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x18, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xd6, 0xe6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x04, 0x7c, 0xce, 0xce, 0xd6, 0xd6, 0xd6, 0xd6, 0xe6, 0xe6, 0x7c, 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0xe0, 0x62, 0x66, 0x6c, 0x18, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00,
+ 0x00, 0x60, 0xe0, 0x62, 0x66, 0x6c, 0x18, 0x30, 0x66, 0xce, 0x9a, 0x3f, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x6c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x66, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/com32/lib/sys/vesa/efi/debug.h b/com32/lib/sys/vesa/efi/debug.h
new file mode 100644
index 00000000..86d085f1
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/debug.h
@@ -0,0 +1,36 @@
+#ifndef LIB_SYS_VESA_DEBUG_H
+#define LIB_SYS_VESA_DEBUG_H
+
+#if 0
+
+#include <stdio.h>
+#include <unistd.h>
+
+ssize_t __serial_write(void *fp, const void *buf, size_t count);
+
+static void debug(const char *str, ...)
+{
+ va_list va;
+ char buf[65536];
+ size_t len;
+
+ va_start(va, str);
+ len = vsnprintf(buf, sizeof buf, str, va);
+ va_end(va);
+
+ if (len >= sizeof buf)
+ len = sizeof buf - 1;
+
+ __serial_write(NULL, buf, len);
+}
+
+#else
+
+static inline void debug(const char *str, ...)
+{
+ (void)str;
+}
+
+#endif
+
+#endif /* LIB_SYS_VESA_DEBUG_H */
diff --git a/com32/lib/sys/vesa/efi/drawtxt.c b/com32/lib/sys/vesa/efi/drawtxt.c
new file mode 100644
index 00000000..85a9e974
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/drawtxt.c
@@ -0,0 +1,317 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <inttypes.h>
+#include <colortbl.h>
+#include <string.h>
+#include "vesa.h"
+#include "video.h"
+#include "fill.h"
+
+/*
+ * Visible cursor information
+ */
+static uint8_t cursor_pattern[FONT_MAX_HEIGHT];
+static struct vesa_char *cursor_pointer = NULL;
+static int cursor_x, cursor_y;
+
+static inline void *copy_dword(void *dst, void *src, size_t dword_count)
+{
+ asm volatile ("rep; movsl":"+D" (dst), "+S"(src), "+c"(dword_count));
+ return dst; /* Updated destination pointer */
+}
+
+static inline __attribute__ ((always_inline))
+uint8_t alpha_val(uint8_t fg, uint8_t bg, uint8_t alpha)
+{
+ unsigned int tmp;
+
+ tmp = __vesacon_srgb_to_linear[fg] * alpha;
+ tmp += __vesacon_srgb_to_linear[bg] * (255 - alpha);
+
+ return __vesacon_linear_to_srgb[tmp >> 12];
+}
+
+static uint32_t alpha_pixel(uint32_t fg, uint32_t bg)
+{
+ uint8_t alpha = fg >> 24;
+ uint8_t fg_r = fg >> 16;
+ uint8_t fg_g = fg >> 8;
+ uint8_t fg_b = fg;
+ uint8_t bg_r = bg >> 16;
+ uint8_t bg_g = bg >> 8;
+ uint8_t bg_b = bg;
+
+ return
+ (alpha_val(fg_r, bg_r, alpha) << 16) |
+ (alpha_val(fg_g, bg_g, alpha) << 8) | (alpha_val(fg_b, bg_b, alpha));
+}
+
+static void vesacon_update_characters(int row, int col, int nrows, int ncols)
+{
+ const int height = __vesacon_font_height;
+ const int width = FONT_WIDTH;
+ uint32_t *bgrowptr, *bgptr, bgval, fgval;
+ uint32_t fgcolor = 0, bgcolor = 0, color;
+ uint8_t chbits = 0, chxbits = 0, chsbits = 0;
+ int i, j, jx, pixrow, pixsrow;
+ struct vesa_char *rowptr, *rowsptr, *cptr, *csptr;
+ unsigned int bytes_per_pixel = __vesacon_bytes_per_pixel;
+ unsigned long pixel_offset;
+ uint32_t row_buffer[__vesa_info.mi.h_res], *rowbufptr;
+ size_t fbrowptr;
+ uint8_t sha;
+
+ pixel_offset = ((row * height + VIDEO_BORDER) * __vesa_info.mi.h_res) +
+ (col * width + VIDEO_BORDER);
+
+ bgrowptr = &__vesacon_background[pixel_offset];
+ fbrowptr = (row * height + VIDEO_BORDER) * __vesa_info.mi.logical_scan +
+ (col * width + VIDEO_BORDER) * bytes_per_pixel;
+
+ /* Note that we keep a 1-character guard area around the real text area... */
+ rowptr = &__vesacon_text_display[(row+1)*(__vesacon_text_cols+2)+(col+1)];
+ rowsptr = rowptr - ((__vesacon_text_cols+2)+1);
+ pixrow = 0;
+ pixsrow = height - 1;
+
+ for (i = height * nrows; i >= 0; i--) {
+ bgptr = bgrowptr;
+ rowbufptr = row_buffer;
+
+ cptr = rowptr;
+ csptr = rowsptr;
+
+ chsbits = __vesacon_graphics_font[csptr->ch][pixsrow];
+ if (__unlikely(csptr == cursor_pointer))
+ chsbits |= cursor_pattern[pixsrow];
+ sha = console_color_table[csptr->attr].shadow;
+ chsbits &= (sha & 0x02) ? 0xff : 0x00;
+ chsbits ^= (sha & 0x01) ? 0xff : 0x00;
+ chsbits <<= (width - 2);
+ csptr++;
+
+ /* Draw two pixels beyond the end of the line. One for the shadow,
+ and one to make sure we have a whole dword of data for the copy
+ operation at the end. Note that this code depends on the fact that
+ all characters begin on dword boundaries in the frame buffer. */
+
+ for (jx = 1, j = width * ncols + 1; j >= 0; j--) {
+ chbits <<= 1;
+ chsbits <<= 1;
+ chxbits <<= 1;
+
+ switch (jx) {
+ case 1:
+ chbits = __vesacon_graphics_font[cptr->ch][pixrow];
+ if (__unlikely(cptr == cursor_pointer))
+ chbits |= cursor_pattern[pixrow];
+ sha = console_color_table[cptr->attr].shadow;
+ chxbits = chbits;
+ chxbits &= (sha & 0x02) ? 0xff : 0x00;
+ chxbits ^= (sha & 0x01) ? 0xff : 0x00;
+ fgcolor = console_color_table[cptr->attr].argb_fg;
+ bgcolor = console_color_table[cptr->attr].argb_bg;
+ cptr++;
+ jx--;
+ break;
+ case 0:
+ chsbits = __vesacon_graphics_font[csptr->ch][pixsrow];
+ if (__unlikely(csptr == cursor_pointer))
+ chsbits |= cursor_pattern[pixsrow];
+ sha = console_color_table[csptr->attr].shadow;
+ chsbits &= (sha & 0x02) ? 0xff : 0x00;
+ chsbits ^= (sha & 0x01) ? 0xff : 0x00;
+ csptr++;
+ jx = width - 1;
+ break;
+ default:
+ jx--;
+ break;
+ }
+
+ /* If this pixel is raised, use the offsetted value */
+ bgval = (chxbits & 0x80)
+ ? bgptr[__vesa_info.mi.h_res + 1] : *bgptr;
+ bgptr++;
+
+ /* If this pixel is set, use the fg color, else the bg color */
+ fgval = (chbits & 0x80) ? fgcolor : bgcolor;
+
+ /* Produce the combined color pixel value */
+ color = alpha_pixel(fgval, bgval);
+
+ /* Apply the shadow (75% shadow) */
+ if ((chsbits & ~chxbits) & 0x80) {
+ color >>= 2;
+ color &= 0x3f3f3f;
+ }
+
+ *rowbufptr++ = color;
+ }
+
+ /* Copy to frame buffer */
+ __vesacon_copy_to_screen(fbrowptr, row_buffer, rowbufptr - row_buffer);
+
+ bgrowptr += __vesa_info.mi.h_res;
+ fbrowptr += __vesa_info.mi.logical_scan;
+
+ if (++pixrow == height) {
+ rowptr += __vesacon_text_cols + 2;
+ pixrow = 0;
+ }
+ if (++pixsrow == height) {
+ rowsptr += __vesacon_text_cols + 2;
+ pixsrow = 0;
+ }
+ }
+}
+
+/* Bounding box for changed text. The (x1, y1) coordinates are +1! */
+static unsigned int upd_x0 = -1U, upd_x1, upd_y0 = -1U, upd_y1;
+
+/* Update the range already touched by various variables */
+void __vesacon_doit(void)
+{
+ if (upd_x1 > upd_x0 && upd_y1 > upd_y0) {
+ vesacon_update_characters(upd_y0, upd_x0, upd_y1 - upd_y0,
+ upd_x1 - upd_x0);
+ upd_x0 = upd_y0 = -1U;
+ upd_x1 = upd_y1 = 0;
+ }
+}
+
+/* Mark a range for update; note argument sequence is the same as
+ vesacon_update_characters() */
+static inline void vesacon_touch(int row, int col, int rows, int cols)
+{
+ unsigned int y0 = row;
+ unsigned int x0 = col;
+ unsigned int y1 = y0 + rows;
+ unsigned int x1 = x0 + cols;
+
+ if (y0 < upd_y0)
+ upd_y0 = y0;
+ if (y1 > upd_y1)
+ upd_y1 = y1;
+ if (x0 < upd_x0)
+ upd_x0 = x0;
+ if (x1 > upd_x1)
+ upd_x1 = x1;
+}
+
+/* Erase a region of the screen */
+void __vesacon_erase(int x0, int y0, int x1, int y1, attr_t attr)
+{
+ int y;
+ struct vesa_char *ptr = &__vesacon_text_display
+ [(y0 + 1) * (__vesacon_text_cols + 2) + (x0 + 1)];
+ struct vesa_char fill = {
+ .ch = ' ',
+ .attr = attr,
+ };
+ int ncols = x1 - x0 + 1;
+
+ for (y = y0; y <= y1; y++) {
+ vesacon_fill(ptr, fill, ncols);
+ ptr += __vesacon_text_cols + 2;
+ }
+
+ vesacon_touch(y0, x0, y1 - y0 + 1, ncols);
+}
+
+/* Scroll the screen up */
+void __vesacon_scroll_up(int nrows, attr_t attr)
+{
+ struct vesa_char *fromptr = &__vesacon_text_display
+ [(nrows + 1) * (__vesacon_text_cols + 2)];
+ struct vesa_char *toptr = &__vesacon_text_display
+ [(__vesacon_text_cols + 2)];
+ int dword_count =
+ (__vesacon_text_rows - nrows) * (__vesacon_text_cols + 2);
+ struct vesa_char fill = {
+ .ch = ' ',
+ .attr = attr,
+ };
+
+ toptr = copy_dword(toptr, fromptr, dword_count);
+
+ dword_count = nrows * (__vesacon_text_cols + 2);
+
+ vesacon_fill(toptr, fill, dword_count);
+
+ vesacon_touch(0, 0, __vesacon_text_rows, __vesacon_text_cols);
+}
+
+/* Draw one character text at a specific area of the screen */
+void __vesacon_write_char(int x, int y, uint8_t ch, attr_t attr)
+{
+ struct vesa_char *ptr = &__vesacon_text_display
+ [(y + 1) * (__vesacon_text_cols + 2) + (x + 1)];
+
+ ptr->ch = ch;
+ ptr->attr = attr;
+
+ vesacon_touch(y, x, 1, 1);
+}
+
+void __vesacon_set_cursor(int x, int y, bool visible)
+{
+ struct vesa_char *ptr = &__vesacon_text_display
+ [(y + 1) * (__vesacon_text_cols + 2) + (x + 1)];
+
+ if (cursor_pointer)
+ vesacon_touch(cursor_y, cursor_x, 1, 1);
+
+ if (!visible) {
+ /* Invisible cursor */
+ cursor_pointer = NULL;
+ } else {
+ cursor_pointer = ptr;
+ vesacon_touch(y, x, 1, 1);
+ }
+
+ cursor_x = x;
+ cursor_y = y;
+}
+
+void __vesacon_init_cursor(int font_height)
+{
+ int r0 = font_height - (font_height < 10 ? 2 : 3);
+
+ if (r0 < 0)
+ r0 = 0;
+
+ memset(cursor_pattern, 0, font_height);
+ cursor_pattern[r0] = 0xff;
+ cursor_pattern[r0 + 1] = 0xff;
+}
+
+void __vesacon_redraw_text(void)
+{
+ vesacon_update_characters(0, 0, __vesacon_text_rows, __vesacon_text_cols);
+}
diff --git a/com32/lib/sys/vesa/efi/fill.h b/com32/lib/sys/vesa/efi/fill.h
new file mode 100644
index 00000000..5a43c728
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/fill.h
@@ -0,0 +1,63 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef LIB_SYS_VESA_FILL_H
+#define LIB_SYS_VESA_FILL_H
+
+#include "video.h"
+
+/* Fill a number of characters. */
+static inline struct vesa_char *vesacon_fill(struct vesa_char *ptr,
+ struct vesa_char fill,
+ unsigned int count)
+{
+ switch (sizeof(struct vesa_char)) {
+ case 1:
+ asm volatile ("rep; stosb":"+D" (ptr), "+c"(count)
+ :"a"(fill)
+ :"memory");
+ break;
+ case 2:
+ asm volatile ("rep; stosw":"+D" (ptr), "+c"(count)
+ :"a"(fill)
+ :"memory");
+ break;
+ case 4:
+ asm volatile ("rep; stosl":"+D" (ptr), "+c"(count)
+ :"a"(fill)
+ :"memory");
+ break;
+ default:
+ while (count--)
+ *ptr++ = fill;
+ break;
+ }
+
+ return ptr;
+}
+
+#endif /* LIB_SYS_VESA_FILL_H */
diff --git a/com32/lib/sys/vesa/efi/fmtpixel.c b/com32/lib/sys/vesa/efi/fmtpixel.c
new file mode 100644
index 00000000..381fc216
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/fmtpixel.c
@@ -0,0 +1,101 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * fmtpixel.c
+ *
+ * Functions to format a single pixel
+ */
+
+#include <inttypes.h>
+#include "video.h"
+
+/*
+ * Format a sequence of pixels. The first argument is the line buffer;
+ * we can use it to write up to 4 bytes past the end of the last pixel.
+ * Return the place we should be copying from, this is usually the
+ * buffer address, but doesn't *have* to be.
+ */
+
+static const void *format_pxf_bgra32(void *ptr, const uint32_t * p, size_t n)
+{
+ (void)ptr;
+ (void)n;
+ return p; /* No conversion needed! */
+}
+
+static const void *format_pxf_bgr24(void *ptr, const uint32_t * p, size_t n)
+{
+ char *q = ptr;
+
+ while (n--) {
+ *(uint32_t *) q = *p++;
+ q += 3;
+ }
+ return ptr;
+}
+
+static const void *format_pxf_le_rgb16_565(void *ptr, const uint32_t * p,
+ size_t n)
+{
+ uint32_t bgra;
+ uint16_t *q = ptr;
+
+ while (n--) {
+ bgra = *p++;
+ *q++ =
+ ((bgra >> 3) & 0x1f) +
+ ((bgra >> (2 + 8 - 5)) & (0x3f << 5)) +
+ ((bgra >> (3 + 16 - 11)) & (0x1f << 11));
+ }
+ return ptr;
+}
+
+static const void *format_pxf_le_rgb15_555(void *ptr, const uint32_t * p,
+ size_t n)
+{
+ uint32_t bgra;
+ uint16_t *q = ptr;
+
+ while (n--) {
+ bgra = *p++;
+ *q++ =
+ ((bgra >> 3) & 0x1f) +
+ ((bgra >> (2 + 8 - 5)) & (0x1f << 5)) +
+ ((bgra >> (3 + 16 - 10)) & (0x1f << 10));
+ }
+ return ptr;
+}
+
+__vesacon_format_pixels_t __vesacon_format_pixels;
+
+const __vesacon_format_pixels_t __vesacon_format_pixels_list[PXF_NONE] = {
+ [PXF_BGRA32] = format_pxf_bgra32,
+ [PXF_BGR24] = format_pxf_bgr24,
+ [PXF_LE_RGB16_565] = format_pxf_le_rgb16_565,
+ [PXF_LE_RGB15_555] = format_pxf_le_rgb15_555,
+};
diff --git a/com32/lib/sys/vesa/efi/i915resolution.c b/com32/lib/sys/vesa/efi/i915resolution.c
new file mode 100644
index 00000000..6ebb04d3
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/i915resolution.c
@@ -0,0 +1,795 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Based on:
+ *
+ * 915 resolution by steve tomljenovic
+ *
+ * This was tested only on Sony VGN-FS550. Use at your own risk
+ *
+ * This code is based on the techniques used in :
+ *
+ * - 855patch. Many thanks to Christian Zietz (czietz gmx net)
+ * for demonstrating how to shadow the VBIOS into system RAM
+ * and then modify it.
+ *
+ * - 1280patch by Andrew Tipton (andrewtipton null li).
+ *
+ * - 855resolution by Alain Poirier
+ *
+ * This source code is into the public domain.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <string.h>
+#include <sys/io.h>
+#include <sys/cpu.h>
+#include <sys/pci.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdbool.h>
+#include "video.h"
+#include "debug.h"
+
+#define VBIOS_START 0xc0000
+#define VBIOS_SIZE 0x10000
+
+#define MODE_TABLE_OFFSET_845G 617
+
+#define VERSION "0.5.3"
+
+#define ATI_SIGNATURE1 "ATI MOBILITY RADEON"
+#define ATI_SIGNATURE2 "ATI Technologies Inc"
+#define NVIDIA_SIGNATURE "NVIDIA Corp"
+#define INTEL_SIGNATURE "Intel Corp"
+
+typedef unsigned char * address;
+
+typedef enum {
+ CT_UNKWN, CT_830, CT_845G, CT_855GM, CT_865G, CT_915G, CT_915GM,
+ CT_945G, CT_945GM, CT_946GZ, CT_G965, CT_Q965, CT_945GME,
+ CHIPSET_TYPES
+} chipset_type;
+
+typedef enum {
+ BT_UNKWN, BT_1, BT_2, BT_3
+} bios_type;
+
+static int freqs[] = { 60, 75, 85 };
+
+typedef struct {
+ uint8_t mode;
+ uint8_t bits_per_pixel;
+ uint16_t resolution;
+ uint8_t unknown;
+} __attribute__((packed)) vbios_mode;
+
+typedef struct {
+ uint16_t clock; /* Clock frequency in 10 kHz */
+ uint8_t x1;
+ uint8_t x_total;
+ uint8_t x2;
+ uint8_t y1;
+ uint8_t y_total;
+ uint8_t y2;
+} __attribute__((packed)) vbios_resolution_type1;
+
+typedef struct {
+ uint32_t clock;
+
+ uint16_t x1;
+ uint16_t htotal;
+ uint16_t x2;
+ uint16_t hblank;
+ uint16_t hsyncstart;
+ uint16_t hsyncend;
+
+ uint16_t y1;
+ uint16_t vtotal;
+ uint16_t y2;
+ uint16_t vblank;
+ uint16_t vsyncstart;
+ uint16_t vsyncend;
+} __attribute__((packed)) vbios_modeline_type2;
+
+typedef struct {
+ uint8_t xchars;
+ uint8_t ychars;
+ uint8_t unknown[4];
+
+ vbios_modeline_type2 modelines[];
+} __attribute__((packed)) vbios_resolution_type2;
+
+typedef struct {
+ uint32_t clock;
+
+ uint16_t x1;
+ uint16_t htotal;
+ uint16_t x2;
+ uint16_t hblank;
+ uint16_t hsyncstart;
+ uint16_t hsyncend;
+
+ uint16_t y1;
+ uint16_t vtotal;
+ uint16_t y2;
+ uint16_t vblank;
+ uint16_t vsyncstart;
+ uint16_t vsyncend;
+
+ uint16_t timing_h;
+ uint16_t timing_v;
+
+ uint8_t unknown[6];
+} __attribute__((packed)) vbios_modeline_type3;
+
+typedef struct {
+ unsigned char unknown[6];
+
+ vbios_modeline_type3 modelines[];
+} __attribute__((packed)) vbios_resolution_type3;
+
+
+typedef struct {
+ unsigned int chipset_id;
+ chipset_type chipset;
+ bios_type bios;
+
+ address bios_ptr;
+
+ vbios_mode * mode_table;
+ unsigned int mode_table_size;
+
+ uint8_t b1, b2;
+
+ bool unlocked;
+} vbios_map;
+
+#if 0 /* Debugging hacks */
+static void good_marker(int x)
+{
+ ((uint16_t *)0xb8000)[x] = 0x2f30 - ((x & 0xf0) << 4) + (x & 0x0f);
+}
+
+static void bad_marker(int x)
+{
+ ((uint16_t *)0xb8000)[x] = 0x4f30 - ((x & 0xf0) << 4) + (x & 0x0f);
+}
+
+static void status(const char *fmt, ...)
+{
+ va_list ap;
+ char msg[81], *p;
+ int i;
+ uint16_t *q;
+
+ memset(msg, 0, sizeof msg);
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof msg, fmt, ap);
+ va_end(ap);
+ p = msg;
+ q = (uint16_t *)0xb8000 + 80;
+ for (i = 0; i < 80; i++)
+ *q++ = *p++ + 0x1f00;
+}
+#else
+static inline void good_marker(int x) { (void)x; }
+static inline void bad_marker(int x) { (void)x; }
+static inline void status(const char *fmt, ...) { (void)fmt; }
+#endif
+
+static unsigned int get_chipset_id(void) {
+ return pci_readl(0x80000000);
+}
+
+static chipset_type get_chipset(unsigned int id) {
+ chipset_type type;
+
+ switch (id) {
+ case 0x35758086:
+ type = CT_830;
+ break;
+
+ case 0x25608086:
+ type = CT_845G;
+ break;
+
+ case 0x35808086:
+ type = CT_855GM;
+ break;
+
+ case 0x25708086:
+ type = CT_865G;
+ break;
+
+ case 0x25808086:
+ type = CT_915G;
+ break;
+
+ case 0x25908086:
+ type = CT_915GM;
+ break;
+
+ case 0x27708086:
+ type = CT_945G;
+ break;
+
+ case 0x27a08086:
+ type = CT_945GM;
+ break;
+
+ case 0x29708086:
+ type = CT_946GZ;
+ break;
+
+ case 0x29a08086:
+ type = CT_G965;
+ break;
+
+ case 0x29908086:
+ type = CT_Q965;
+ break;
+
+ case 0x27ac8086:
+ type = CT_945GME;
+ break;
+
+ default:
+ type = CT_UNKWN;
+ break;
+ }
+
+ return type;
+}
+
+
+static vbios_resolution_type1 * map_type1_resolution(vbios_map * map,
+ uint16_t res)
+{
+ vbios_resolution_type1 * ptr = ((vbios_resolution_type1*)(map->bios_ptr + res));
+ return ptr;
+}
+
+static vbios_resolution_type2 * map_type2_resolution(vbios_map * map,
+ uint16_t res)
+{
+ vbios_resolution_type2 * ptr = ((vbios_resolution_type2*)(map->bios_ptr + res));
+ return ptr;
+}
+
+static vbios_resolution_type3 * map_type3_resolution(vbios_map * map,
+ uint16_t res)
+{
+ vbios_resolution_type3 * ptr = ((vbios_resolution_type3*)(map->bios_ptr + res));
+ return ptr;
+}
+
+
+static bool detect_bios_type(vbios_map * map, int entry_size)
+{
+ unsigned int i;
+ uint16_t r1, r2;
+
+ r1 = r2 = 32000;
+
+ for (i = 0; i < map->mode_table_size; i++) {
+ if (map->mode_table[i].resolution <= r1) {
+ r1 = map->mode_table[i].resolution;
+ } else if (map->mode_table[i].resolution <= r2) {
+ r2 = map->mode_table[i].resolution;
+ }
+ }
+
+ return ((r2-r1-6) % entry_size) == 0;
+}
+
+static inline void close_vbios(vbios_map *map)
+{
+ (void)map;
+}
+
+static vbios_map * open_vbios(void)
+{
+ static vbios_map _map;
+ vbios_map * const map = &_map;
+
+ memset(&_map, 0, sizeof _map);
+
+ /*
+ * Determine chipset
+ */
+ map->chipset_id = get_chipset_id();
+ good_marker(0x10);
+ map->chipset = get_chipset(map->chipset_id);
+ good_marker(0x11);
+
+ /*
+ * Map the video bios to memory
+ */
+ map->bios_ptr = (void *)VBIOS_START;
+
+ /*
+ * check if we have ATI Radeon
+ */
+
+ if (memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE1, strlen(ATI_SIGNATURE1)) ||
+ memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE2, strlen(ATI_SIGNATURE2)) ) {
+ debug("ATI chipset detected. 915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+ return NULL;
+ }
+
+ /*
+ * check if we have NVIDIA
+ */
+
+ if (memmem(map->bios_ptr, VBIOS_SIZE, NVIDIA_SIGNATURE, strlen(NVIDIA_SIGNATURE))) {
+ debug("NVIDIA chipset detected. 915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+ return NULL;
+ }
+
+ /*
+ * check if we have Intel
+ */
+
+ if (map->chipset == CT_UNKWN && memmem(map->bios_ptr, VBIOS_SIZE, INTEL_SIGNATURE, strlen(INTEL_SIGNATURE))) {
+ debug("Intel chipset detected. However, 915resolution was unable to determine the chipset type.\r\n");
+
+ debug("Chipset Id: %x\r\n", map->chipset_id);
+
+ debug("Please report this problem to stomljen@yahoo.com\r\n");
+
+ close_vbios(map);
+ return NULL;
+ }
+
+ /*
+ * check for others
+ */
+
+ if (map->chipset == CT_UNKWN) {
+ debug("Unknown chipset type and unrecognized bios.\r\n");
+ debug("915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+
+ debug("Chipset Id: %x\r\n", map->chipset_id);
+ close_vbios(map);
+ return NULL;
+ }
+
+ /*
+ * Figure out where the mode table is
+ */
+ good_marker(0x12);
+
+ {
+ address p = map->bios_ptr + 16;
+ address limit = map->bios_ptr + VBIOS_SIZE - (3 * sizeof(vbios_mode));
+
+ while (p < limit && map->mode_table == 0) {
+ vbios_mode * mode_ptr = (vbios_mode *) p;
+
+ if (((mode_ptr[0].mode & 0xf0) == 0x30) && ((mode_ptr[1].mode & 0xf0) == 0x30) &&
+ ((mode_ptr[2].mode & 0xf0) == 0x30) && ((mode_ptr[3].mode & 0xf0) == 0x30)) {
+
+ map->mode_table = mode_ptr;
+ }
+
+ p++;
+ }
+
+ if (map->mode_table == 0) {
+ debug("Unable to locate the mode table.\r\n");
+ close_vbios(map);
+ return NULL;
+ }
+ }
+ good_marker(0x13);
+
+ /*
+ * Determine size of mode table
+ */
+
+ {
+ vbios_mode * mode_ptr = map->mode_table;
+
+ while (mode_ptr->mode != 0xff) {
+ map->mode_table_size++;
+ mode_ptr++;
+ }
+ }
+ good_marker(0x14);
+ status("mode_table_size = %d", map->mode_table_size);
+
+ /*
+ * Figure out what type of bios we have
+ * order of detection is important
+ */
+
+ if (detect_bios_type(map, sizeof(vbios_modeline_type3))) {
+ map->bios = BT_3;
+ }
+ else if (detect_bios_type(map, sizeof(vbios_modeline_type2))) {
+ map->bios = BT_2;
+ }
+ else if (detect_bios_type(map, sizeof(vbios_resolution_type1))) {
+ map->bios = BT_1;
+ }
+ else {
+ debug("Unable to determine bios type.\r\n");
+ debug("Mode Table Offset: $C0000 + $%x\r\n", ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr));
+ debug("Mode Table Entries: %u\r\n", map->mode_table_size);
+ bad_marker(0x15);
+ return NULL;
+ }
+ good_marker(0x15);
+
+ return map;
+}
+
+static void unlock_vbios(vbios_map * map)
+{
+ assert(!map->unlocked);
+
+ map->unlocked = true;
+
+ switch (map->chipset) {
+ case CT_UNKWN:
+ case CHIPSET_TYPES: /* Shut up gcc */
+ break;
+ case CT_830:
+ case CT_855GM:
+ map->b1 = pci_readb(0x8000005a);
+ pci_writeb(0x33, 0x8000005a);
+ break;
+ case CT_845G:
+ case CT_865G:
+ case CT_915G:
+ case CT_915GM:
+ case CT_945G:
+ case CT_945GM:
+ case CT_945GME:
+ case CT_946GZ:
+ case CT_G965:
+ case CT_Q965:
+ map->b1 = pci_readb(0x80000091);
+ map->b2 = pci_readb(0x80000092);
+ pci_writeb(0x33, 0x80000091);
+ pci_writeb(0x33, 0x80000092);
+ break;
+ }
+
+#if DEBUG
+ {
+ unsigned int t = inl(0xcfc);
+ debug("unlock PAM: (0x%08x)\r\n", t);
+ }
+#endif
+}
+
+static void relock_vbios(vbios_map * map)
+{
+ assert(map->unlocked);
+ map->unlocked = false;
+
+ switch (map->chipset) {
+ case CT_UNKWN:
+ case CHIPSET_TYPES: /* Shut up gcc */
+ break;
+ case CT_830:
+ case CT_855GM:
+ pci_writeb(map->b1, 0x8000005a);
+ break;
+ case CT_845G:
+ case CT_865G:
+ case CT_915G:
+ case CT_915GM:
+ case CT_945G:
+ case CT_945GM:
+ case CT_945GME:
+ case CT_946GZ:
+ case CT_G965:
+ case CT_Q965:
+ pci_writeb(map->b1, 0x80000091);
+ pci_writeb(map->b2, 0x80000092);
+ break;
+ }
+
+#if DEBUG
+ {
+ unsigned int t = inl(0xcfc);
+ debug("relock PAM: (0x%08x)\r\n", t);
+ }
+#endif
+}
+
+#if 0
+static void list_modes(vbios_map *map, unsigned int raw)
+{
+ unsigned int i, x, y;
+
+ for (i=0; i < map->mode_table_size; i++) {
+ switch(map->bios) {
+ case BT_1:
+ {
+ vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
+
+ x = ((((unsigned int) res->x2) & 0xf0) << 4) | res->x1;
+ y = ((((unsigned int) res->y2) & 0xf0) << 4) | res->y1;
+
+ if (x != 0 && y != 0) {
+ debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+ }
+
+ if (raw)
+ {
+ debug("Mode %02x (raw) :\r\n\t%02x %02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n", map->mode_table[i].mode, res->unknow1[0],res->unknow1[1], res->x1,res->x_total,res->x2,res->y1,res->y_total,res->y2);
+ }
+
+ }
+ break;
+ case BT_2:
+ {
+ vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
+
+ x = res->modelines[0].x1+1;
+ y = res->modelines[0].y1+1;
+
+ if (x != 0 && y != 0) {
+ debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+ }
+ }
+ break;
+ case BT_3:
+ {
+ vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
+
+ x = res->modelines[0].x1+1;
+ y = res->modelines[0].y1+1;
+
+ if (x != 0 && y != 0) {
+ debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+ }
+ }
+ break;
+ case BT_UNKWN:
+ break;
+ }
+ }
+}
+#endif
+
+static void gtf_timings(int x, int y, int freq, uint32_t *clock,
+ uint16_t *hsyncstart, uint16_t *hsyncend, uint16_t *hblank,
+ uint16_t *vsyncstart, uint16_t *vsyncend, uint16_t *vblank)
+{
+ int hbl, vbl, vfreq;
+
+ vbl = y + (y+1)/(20000.0/(11*freq) - 1) + 1.5;
+ vfreq = vbl * freq;
+ hbl = 16 * (int)(x * (30.0 - 300000.0 / vfreq) /
+ (70.0 + 300000.0 / vfreq) / 16.0 + 0.5);
+
+ *vsyncstart = y;
+ *vsyncend = y + 3;
+ *vblank = vbl - 1;
+ *hsyncstart = x + hbl / 2 - (x + hbl + 50) / 100 * 8 - 1;
+ *hsyncend = x + hbl / 2 - 1;
+ *hblank = x + hbl - 1;
+ *clock = (x + hbl) * vfreq / 1000;
+}
+
+static int set_mode(vbios_map * map, unsigned int mode,
+ unsigned int x, unsigned int y, unsigned int bp,
+ unsigned int htotal, unsigned int vtotal)
+{
+ int xprev, yprev;
+ unsigned int i, j;
+ int rv = -1;
+
+ for (i=0; i < map->mode_table_size; i++) {
+ if (map->mode_table[i].mode == mode) {
+ switch(map->bios) {
+ case BT_1:
+ {
+ vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
+ uint32_t clock;
+ uint16_t hsyncstart, hsyncend, hblank;
+ uint16_t vsyncstart, vsyncend, vblank;
+
+ if (bp) {
+ map->mode_table[i].bits_per_pixel = bp;
+ }
+
+ gtf_timings(x, y, freqs[0], &clock,
+ &hsyncstart, &hsyncend, &hblank,
+ &vsyncstart, &vsyncend, &vblank);
+
+ status("x = %d, y = %d, clock = %lu, h = %d %d %d, v = %d %d %d\n",
+ x, y, clock,
+ hsyncstart, hsyncend, hblank,
+ vsyncstart, vsyncend, vblank);
+
+ htotal = htotal ? htotal : (unsigned int)hblank+1;
+ vtotal = vtotal ? vtotal : (unsigned int)vblank+1;
+
+ res->clock = clock/10; /* Units appear to be 10 kHz */
+ res->x2 = (((htotal-x) >> 8) & 0x0f) | ((x >> 4) & 0xf0);
+ res->x1 = (x & 0xff);
+
+ res->y2 = (((vtotal-y) >> 8) & 0x0f) | ((y >> 4) & 0xf0);
+ res->y1 = (y & 0xff);
+ if (htotal)
+ res->x_total = ((htotal-x) & 0xff);
+
+ if (vtotal)
+ res->y_total = ((vtotal-y) & 0xff);
+
+ rv = 0;
+ }
+ break;
+ case BT_2:
+ {
+ vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
+
+ res->xchars = x / 8;
+ res->ychars = y / 16 - 1;
+ xprev = res->modelines[0].x1;
+ yprev = res->modelines[0].y1;
+
+ for(j=0; j < 3; j++) {
+ vbios_modeline_type2 * modeline = &res->modelines[j];
+
+ if (modeline->x1 == xprev && modeline->y1 == yprev) {
+ modeline->x1 = modeline->x2 = x-1;
+ modeline->y1 = modeline->y2 = y-1;
+
+ gtf_timings(x, y, freqs[j], &modeline->clock,
+ &modeline->hsyncstart, &modeline->hsyncend,
+ &modeline->hblank, &modeline->vsyncstart,
+ &modeline->vsyncend, &modeline->vblank);
+
+ if (htotal)
+ modeline->htotal = htotal;
+ else
+ modeline->htotal = modeline->hblank;
+
+ if (vtotal)
+ modeline->vtotal = vtotal;
+ else
+ modeline->vtotal = modeline->vblank;
+ }
+ }
+
+ rv = 0;
+ }
+ break;
+ case BT_3:
+ {
+ vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
+
+ xprev = res->modelines[0].x1;
+ yprev = res->modelines[0].y1;
+
+ for (j=0; j < 3; j++) {
+ vbios_modeline_type3 * modeline = &res->modelines[j];
+
+ if (modeline->x1 == xprev && modeline->y1 == yprev) {
+ modeline->x1 = modeline->x2 = x-1;
+ modeline->y1 = modeline->y2 = y-1;
+
+ gtf_timings(x, y, freqs[j], &modeline->clock,
+ &modeline->hsyncstart, &modeline->hsyncend,
+ &modeline->hblank, &modeline->vsyncstart,
+ &modeline->vsyncend, &modeline->vblank);
+ if (htotal)
+ modeline->htotal = htotal;
+ else
+ modeline->htotal = modeline->hblank;
+ if (vtotal)
+ modeline->vtotal = vtotal;
+ else
+ modeline->vtotal = modeline->vblank;
+
+ modeline->timing_h = y-1;
+ modeline->timing_v = x-1;
+ }
+ }
+
+ rv = 0;
+ }
+ break;
+ case BT_UNKWN:
+ break;
+ }
+ }
+ }
+
+ return rv;
+}
+
+static inline void display_map_info(vbios_map * map) {
+#ifdef DEBUG
+ static const char * bios_type_names[] =
+ {"UNKNOWN", "TYPE 1", "TYPE 2", "TYPE 3"};
+ static const char * chipset_type_names[] = {
+ "UNKNOWN", "830", "845G", "855GM", "865G", "915G", "915GM", "945G",
+ "945GM", "946GZ", "G965", "Q965", "945GME"
+ };
+
+ debug("Chipset: %s\r\n", chipset_type_names[map->chipset]);
+ debug("BIOS: %s\r\n", bios_type_names[map->bios]);
+
+ debug("Mode Table Offset: $C0000 + $%x\r\n",
+ ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr));
+ debug("Mode Table Entries: %u\r\n", map->mode_table_size);
+#endif
+ (void)map;
+}
+
+int __vesacon_i915resolution(int x, int y)
+{
+ vbios_map * map;
+ unsigned int mode = 0x52; /* 800x600x32 mode in known BIOSes */
+ unsigned int bp = 32; /* 32 bits per pixel */
+ int rv = 0;
+
+ good_marker(0);
+
+ map = open_vbios();
+ if (!map)
+ return -1;
+
+ good_marker(1);
+
+ display_map_info(map);
+
+ debug("\r\n");
+
+ if (mode && x && y) {
+ good_marker(2);
+ cli();
+ good_marker(3);
+ unlock_vbios(map);
+ good_marker(4);
+ rv = set_mode(map, mode, x, y, bp, 0, 0);
+ if (rv)
+ bad_marker(5);
+ else
+ good_marker(5);
+ relock_vbios(map);
+ good_marker(6);
+ sti();
+
+ debug("Patch mode %02x to resolution %dx%d complete\r\n", mode, x, y);
+ }
+ close_vbios(map);
+
+ return rv;
+}
diff --git a/com32/lib/sys/vesa/efi/initvesa.c b/com32/lib/sys/vesa/efi/initvesa.c
new file mode 100644
index 00000000..9bb1f28d
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/initvesa.c
@@ -0,0 +1,617 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2012 H. Peter Anvin - All Rights Reserved
+ * Chandramouli Narayanan - extended for EFI support
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * initvesa.c
+ *
+ * Query the VESA BIOS and select a 640x480x32 mode with local mapping
+ * support, if one exists.
+ */
+
+#include <inttypes.h>
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/fpu.h>
+#include <syslinux/video.h>
+#ifdef SYSLINUX_EFI
+#include <efi.h>
+#include <efilib.h>
+#include <efistdarg.h>
+/* We use cp865_8x16.psf as the standard font for EFI implementation
+ * the header file below contains raw data parsed from cp865_8x16.psf
+ */
+#include "cp865_8x16.h"
+#endif
+#include "vesa.h"
+#include "video.h"
+#include "fill.h"
+#include "debug.h"
+
+struct vesa_info __vesa_info;
+
+struct vesa_char *__vesacon_text_display;
+
+int __vesacon_font_height;
+int __vesacon_text_rows;
+int __vesacon_text_cols;
+enum vesa_pixel_format __vesacon_pixel_format = PXF_NONE;
+unsigned int __vesacon_bytes_per_pixel;
+uint8_t __vesacon_graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT];
+
+uint32_t *__vesacon_background, *__vesacon_shadowfb;
+
+static void unpack_font(uint8_t * dst, uint8_t * src, int height)
+{
+ int i;
+
+ for (i = 0; i < FONT_MAX_CHARS; i++) {
+ memcpy(dst, src, height);
+ memset(dst + height, 0, FONT_MAX_HEIGHT - height);
+
+ dst += FONT_MAX_HEIGHT;
+ src += height;
+ }
+}
+
+static int __constfunc is_power_of_2(unsigned int x)
+{
+ return x && !(x & (x - 1));
+}
+
+static int vesacon_paged_mode_ok(const struct vesa_mode_info *mi)
+{
+ int i;
+
+ if (!is_power_of_2(mi->win_size) ||
+ !is_power_of_2(mi->win_grain) || mi->win_grain > mi->win_size)
+ return 0; /* Impossible... */
+
+ for (i = 0; i < 2; i++) {
+ if ((mi->win_attr[i] & 0x05) == 0x05 && mi->win_seg[i])
+ return 1; /* Usable window */
+ }
+
+ return 0; /* Nope... */
+}
+
+#ifndef SYSLINUX_EFI
+static int vesacon_set_mode(int x, int y)
+{
+ com32sys_t rm;
+ uint8_t *rom_font;
+ uint16_t mode, bestmode, *mode_ptr;
+ struct vesa_info *vi;
+ struct vesa_general_info *gi;
+ struct vesa_mode_info *mi;
+ enum vesa_pixel_format pxf, bestpxf;
+ int err = 0;
+
+ debug("Hello, World!\r\n");
+
+ /* Free any existing data structures */
+ if (__vesacon_background) {
+ free(__vesacon_background);
+ __vesacon_background = NULL;
+ }
+ if (__vesacon_shadowfb) {
+ free(__vesacon_shadowfb);
+ __vesacon_shadowfb = NULL;
+ }
+
+ /* Allocate space in the bounce buffer for these structures */
+ vi = lzalloc(sizeof *vi);
+ if (!vi) {
+ err = 10; /* Out of memory */
+ goto exit;
+ }
+ gi = &vi->gi;
+ mi = &vi->mi;
+
+ memset(&rm, 0, sizeof rm);
+
+ gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
+ rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
+ rm.edi.w[0] = OFFS(gi);
+ rm.es = SEG(gi);
+ __intcall(0x10, &rm, &rm);
+
+ if (rm.eax.w[0] != 0x004F) {
+ err = 1; /* Function call failed */
+ goto exit;
+ }
+ if (gi->signature != VESA_MAGIC) {
+ err = 2; /* No magic */
+ goto exit;
+ }
+ if (gi->version < 0x0102) {
+ err = 3; /* VESA 1.2+ required */
+ goto exit;
+ }
+
+ /* Copy general info */
+ memcpy(&__vesa_info.gi, gi, sizeof *gi);
+
+ /* Search for the proper mode with a suitable color and memory model... */
+
+ mode_ptr = GET_PTR(gi->video_mode_ptr);
+ bestmode = 0;
+ bestpxf = PXF_NONE;
+
+ while ((mode = *mode_ptr++) != 0xFFFF) {
+ mode &= 0x1FF; /* The rest are attributes of sorts */
+
+ debug("Found mode: 0x%04x\r\n", mode);
+
+ memset(mi, 0, sizeof *mi);
+ rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */
+ rm.ecx.w[0] = mode;
+ rm.edi.w[0] = OFFS(mi);
+ rm.es = SEG(mi);
+ __intcall(0x10, &rm, &rm);
+
+ /* Must be a supported mode */
+ if (rm.eax.w[0] != 0x004f)
+ continue;
+
+ debug
+ ("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
+ mi->mode_attr, mi->h_res, mi->v_res, mi->bpp, mi->memory_layout,
+ mi->rpos, mi->gpos, mi->bpos);
+
+ /* Must be an LFB color graphics mode supported by the hardware.
+
+ The bits tested are:
+ 4 - graphics mode
+ 3 - color mode
+ 1 - mode information available (mandatory in VBE 1.2+)
+ 0 - mode supported by hardware
+ */
+ if ((mi->mode_attr & 0x001b) != 0x001b)
+ continue;
+
+ /* Must be the chosen size */
+ if (mi->h_res != x || mi->v_res != y)
+ continue;
+
+ /* We don't support multibank (interlaced memory) modes */
+ /*
+ * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
+ * specification which states that banks == 1 for unbanked modes;
+ * fortunately it does report bank_size == 0 for those.
+ */
+ if (mi->banks > 1 && mi->bank_size) {
+ debug("bad: banks = %d, banksize = %d, pages = %d\r\n",
+ mi->banks, mi->bank_size, mi->image_pages);
+ continue;
+ }
+
+ /* Must be either a flat-framebuffer mode, or be an acceptable
+ paged mode */
+ if (!(mi->mode_attr & 0x0080) && !vesacon_paged_mode_ok(mi)) {
+ debug("bad: invalid paged mode\r\n");
+ continue;
+ }
+
+ /* Must either be a packed-pixel mode or a direct color mode
+ (depending on VESA version ); must be a supported pixel format */
+ pxf = PXF_NONE; /* Not usable */
+
+ if (mi->bpp == 32 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+ mi->bpos == 0)))
+ pxf = PXF_BGRA32;
+ else if (mi->bpp == 24 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+ mi->bpos == 0)))
+ pxf = PXF_BGR24;
+ else if (mi->bpp == 16 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
+ mi->bpos == 0)))
+ pxf = PXF_LE_RGB16_565;
+ else if (mi->bpp == 15 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 &&
+ mi->bpos == 0)))
+ pxf = PXF_LE_RGB15_555;
+
+ if (pxf < bestpxf) {
+ debug("Best mode so far, pxf = %d\r\n", pxf);
+
+ /* Best mode so far... */
+ bestmode = mode;
+ bestpxf = pxf;
+
+ /* Copy mode info */
+ memcpy(&__vesa_info.mi, mi, sizeof *mi);
+ }
+ }
+
+ if (bestpxf == PXF_NONE) {
+ err = 4; /* No mode found */
+ goto exit;
+ }
+
+ mi = &__vesa_info.mi;
+ mode = bestmode;
+ __vesacon_bytes_per_pixel = (mi->bpp + 7) >> 3;
+ __vesacon_format_pixels = __vesacon_format_pixels_list[bestpxf];
+
+ /* Download the SYSLINUX- or BIOS-provided font */
+ __vesacon_font_height = syslinux_font_query(&rom_font);
+ if (!__vesacon_font_height) {
+ /* Get BIOS 8x16 font */
+
+ rm.eax.w[0] = 0x1130; /* Get Font Information */
+ rm.ebx.w[0] = 0x0600; /* Get 8x16 ROM font */
+ __intcall(0x10, &rm, &rm);
+ rom_font = MK_PTR(rm.es, rm.ebp.w[0]);
+ __vesacon_font_height = 16;
+ }
+ unpack_font((uint8_t *) __vesacon_graphics_font, rom_font,
+ __vesacon_font_height);
+
+ /* Now set video mode */
+ rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */
+ if (mi->mode_attr & 0x0080)
+ mode |= 0x4000; /* Request linear framebuffer if supported */
+ rm.ebx.w[0] = mode;
+ __intcall(0x10, &rm, &rm);
+ if (rm.eax.w[0] != 0x004F) {
+ err = 9; /* Failed to set mode */
+ goto exit;
+ }
+
+ __vesacon_background = calloc(mi->h_res*mi->v_res, 4);
+ __vesacon_shadowfb = calloc(mi->h_res*mi->v_res, 4);
+
+ __vesacon_init_copy_to_screen();
+
+ /* Tell syslinux we changed video mode */
+ /* In theory this should be:
+
+ flags = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+
+ However, that would assume all systems that claim to handle text
+ output in VESA modes actually do that... */
+ syslinux_report_video_mode(0x000f, mi->h_res, mi->v_res);
+
+ __vesacon_pixel_format = bestpxf;
+
+exit:
+ if (vi)
+ lfree(vi);
+
+ return err;
+}
+
+#else
+/* EFI GOP support
+ * Note GOP support uses the VESA info structure as much as possible and
+ * extends it as needed for EFI support. Not all of the vesa info structure
+ * is populated. Care must be taken in the routines that rely the vesa
+ * informataion structure
+ */
+static void find_pixmask_bits(uint32_t mask, uint8_t *first_bit, uint8_t *len) {
+ uint8_t bit_pos = 0, bit_len = 0;
+
+ *first_bit = 0;
+ *len = 0;
+ if (mask == 0)
+ return;
+ while (!(mask & 0x1)) {
+ mask = mask >> 1;
+ bit_pos++;
+ }
+ while (mask & 0x1) {
+ mask = mask >> 1;
+ bit_len++;
+ }
+ *first_bit = bit_pos;
+ *len = bit_len;
+}
+static int vesacon_set_mode(int x, int y)
+{
+ EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *gop_mode;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info;
+ EFI_STATUS st;
+ UINT32 mode_num = 0, bestmode;
+ BOOLEAN mode_match = FALSE;
+ UINTN sz_info;
+ struct vesa_info *vi;
+ struct vesa_general_info *gi;
+ struct vesa_mode_info *mi;
+ enum vesa_pixel_format pxf, bestpxf = PXF_NONE;
+ int err = 0;
+
+ //debug("Hello, World!\r\n");
+ printf("Hello, world, entering EFI graphics mode set operation (x=%d, y=%d)\n", x,y);//debug
+ /* At this point, we assume that gnu-efi library is initialized */
+ st = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+ if (EFI_ERROR(st)) {
+ debug("LiblocateProtocol for GOP failed %d\n", st);
+ return 1; /* function call failed */
+ }
+
+ /* We use the VESA info structure to store relevant GOP info as much as possible */
+ gop_mode = GraphicsOutput->Mode;
+
+ /* simply pick the best mode that suits the caller's resolution */
+ for (mode_num = 0; mode_num < gop_mode->MaxMode; mode_num++) {
+ st = uefi_call_wrapper(GraphicsOutput->QueryMode, 4, GraphicsOutput, mode_num, &sz_info, &mode_info);
+ debug("mode_num = %d query_status %d\n", mode_num, st);
+ if (st == EFI_SUCCESS && sz_info >= sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)) {
+ /*
+ Print(L"mode %d ver %d (Hres=%d, Vres=%d) PixlFmt %d ",
+ mode_num,
+ info->Version, info->HorizontalResolution,
+ info->VerticalResolution,
+ info->PixelFormat);
+ if (info->PixelFormat == PixelBitMask)
+ Print(L"PixelBitMask RMask 0x%x GMask 0x%x BMask 0x%x ",
+ info->PixelInformation.RedMask,
+ info->PixelInformation.GreenMask,
+ info->PixelInformation.BlueMask);
+ Print(L"ScanPerLine %d\n", info->PixelsPerScanLine);
+ */
+
+ /* For now, simply pick the best mode that suits caller's resolution (x,y)
+ * FIXME: Consider any additional criteria for matching mode
+ */
+ mode_match = ((uint32_t)x == mode_info->HorizontalResolution && (uint32_t)y == mode_info->VerticalResolution);
+ debug("mode %d hres=%d vres=%d\n", mode_num, mode_info->HorizontalResolution, mode_info->VerticalResolution);
+ if (mode_match) {
+ bestmode = mode_num;
+ break;
+ }
+ }
+ }
+
+ if (!mode_match) {
+ debug("No matching mode available for resolution (x=%d, y=%d)\n", x, y);
+ return 4; /* no mode found */
+ }
+
+ /* Allocate space in the bounce buffer for these structures */
+ vi = lzalloc(sizeof *vi);
+ if (!vi) {
+ err = 10; /* Out of memory */
+ goto exit;
+ }
+ /* Note that the generic info is untouched as we don't find any relevance to EFI */
+ gi = &vi->gi;
+ mi = &vi->mi;
+ /* Set up mode-specific information */
+ mi->h_res = x;
+ mi->v_res = y;
+ mi->lfb_ptr = (uint8_t *)(VOID *)(UINTN)gop_mode->FrameBufferBase;
+ mi->lfb_size = gop_mode->FrameBufferSize;
+
+ /* FIXME:
+ * The code below treats bpp == lfb_depth ; verify
+ */
+
+ switch (mode_info->PixelFormat) {
+ case PixelRedGreenBlueReserved8BitPerColor:
+ mi->mode_attr = 0x0080; /* supports physical frame buffer */
+ mi->bpp = sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * 8;
+ mi->rpos = 0;
+ mi->gpos = 8;
+ mi->bpos = 16;
+ mi->resv_pos = 24;
+ mi->resv_size = 8;
+ mi->logical_scan = mi->lfb_line_size = (mode_info->PixelsPerScanLine * mi->bpp) / 8;
+ bestpxf = PXF_BGRA32;
+ break;
+ case PixelBlueGreenRedReserved8BitPerColor:
+ mi->mode_attr = 0x0080; /* supports physical frame buffer */
+ mi->bpp = sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * 8;
+ mi->bpos = 0;
+ mi->gpos = 8;
+ mi->rpos = 16;
+ mi->resv_pos = 24;
+ mi->resv_size = 8;
+ mi->logical_scan = mi->lfb_line_size = (mode_info->PixelsPerScanLine * mi->bpp) / 8;
+ bestpxf = PXF_BGRA32;
+ break;
+ case PixelBitMask:
+ mi->mode_attr = 0x0080; /* supports physical frame buffer */
+ find_pixmask_bits(mode_info->PixelInformation.RedMask,
+ &mi->rpos, &mi->lfb_rsize);
+ find_pixmask_bits(mode_info->PixelInformation.GreenMask,
+ &mi->gpos, &mi->lfb_gsize);
+ find_pixmask_bits(mode_info->PixelInformation.BlueMask,
+ &mi->bpos, &mi->lfb_bsize);
+ find_pixmask_bits(mode_info->PixelInformation.ReservedMask,
+ &mi->resv_pos, &mi->resv_size);
+ mi->bpp = mi->lfb_rsize + mi->lfb_gsize +
+ mi->lfb_bsize + mi->lfb_resv_size;
+ mi->logical_scan = mi->lfb_line_size = (mode_info->PixelsPerScanLine * mi->bpp) / 8;
+ bestpxf = PXF_BGRA32; /* FIXME: correct? */
+ break;
+ case PixelBltOnly:
+ /* FIXME: unsupported */
+ mi->mode_attr = 0x0000; /* no support for physical frame buffer */
+ err = 4; /* no mode found */
+ goto exit;
+ break;
+ default:
+ /* should not get here, but let's error out */
+ err = 4; /* no mode found */
+ goto exit;
+ break;
+ }
+
+ memcpy(&__vesa_info.mi, mi, sizeof *mi);
+ mi = &__vesa_info.mi;
+ /* set up font info
+ * For now, font info is stored as raw data and used
+ * as such. Altenatively, the font data stored in a file
+ * could be read and parsed. (note: for this, EFI
+ * file support should be exposed via firmware structure)
+ */
+ __vesacon_font_height = cp865_8x16_font_height;
+ unpack_font((uint8_t *) __vesacon_graphics_font, cp865_8x16_font_data,
+ __vesacon_font_height);
+
+ /* Free any existing data structures */
+ if (__vesacon_background) {
+ free(__vesacon_background);
+ __vesacon_background = NULL;
+ }
+ if (__vesacon_shadowfb) {
+ free(__vesacon_shadowfb);
+ __vesacon_shadowfb = NULL;
+ }
+
+ __vesacon_bytes_per_pixel = (mi->bpp + 7) >> 3;
+ __vesacon_format_pixels = __vesacon_format_pixels_list[bestpxf];
+
+ /* Now set video mode */
+ st = uefi_call_wrapper(GraphicsOutput->SetMode, 2, GraphicsOutput, bestmode);
+ if (EFI_ERROR(st)) {
+ err = 9; /* Failed to set mode */
+ goto exit;
+ }
+
+ /* TODO: Follow the code usage of vesacon_background & vesacon_shadowfb */
+ /*
+ __vesacon_background = calloc(mi->h_res*mi->v_res, 4);
+ __vesacon_shadowfb = calloc(mi->h_res*mi->v_res, 4);
+ */
+ /* FIXME: the allocation takes the possible padding into account
+ * whereas BIOS code simply allocates hres * vres bytes.
+ * Which is correct?
+ */
+ /*
+ * For performance reasons, or due to hardware restrictions, scan lines
+ * may be padded to an amount of memory alignment. These padding pixel elements
+ * are outside the area covered by HorizontalResolution and are not visible.
+ * For direct frame buffer access, this number is used as a span between starts
+ * of pixel lines in video memory. Based on the size of an individual pixel element
+ * and PixelsPerScanline, the offset in video memory from pixel element (x, y)
+ * to pixel element (x, y+1) has to be calculated as
+ * "sizeof( PixelElement ) * PixelsPerScanLine", and not
+ * "sizeof( PixelElement ) * HorizontalResolution", though in many cases
+ * those values can coincide.
+ */
+
+ __vesacon_background = calloc(mi->lfb_line_size*mi->v_res, 4);
+ __vesacon_shadowfb = calloc(mi->lfb_line_size*mi->v_res, 4);
+
+ __vesacon_init_copy_to_screen();
+
+ /* Tell syslinux we changed video mode
+ * FIXME: The following call is BIOS-centric. I don't see an EFI-equivalent
+ * syslinux_report_video_mode(0x000f, mi->h_res, mi->v_res);
+ */
+
+ __vesacon_pixel_format = bestpxf;
+
+exit:
+ if (vi)
+ lfree(vi);
+
+ return err;
+}
+#endif /* SYSLINUX_EFI */
+
+/* FIXME:
+ * Does init_text_display need an EFI counterpart?
+ * e.g. vesa_char may need to setup UNICODE char for EFI
+ * and the number of screen chars may need to be sized up
+ * accordingly. This may also require turning byte strings
+ * into unicode strings in the framebuffer
+ * Possibly, revisit vesacon_fill() for EFI.
+ */
+
+static int init_text_display(void)
+{
+ size_t nchars;
+ struct vesa_char *ptr;
+ struct vesa_char def_char = {
+ .ch = ' ',
+ .attr = 0,
+ };
+
+ if (__vesacon_text_display)
+ free(__vesacon_text_display);
+
+ __vesacon_text_cols = TEXT_PIXEL_COLS / FONT_WIDTH;
+ __vesacon_text_rows = TEXT_PIXEL_ROWS / __vesacon_font_height;
+ nchars = (__vesacon_text_cols+2) * (__vesacon_text_rows+2);
+
+ __vesacon_text_display = ptr = malloc(nchars * sizeof(struct vesa_char));
+
+ if (!ptr)
+ return -1;
+
+ vesacon_fill(ptr, def_char, nchars);
+ __vesacon_init_cursor(__vesacon_font_height);
+
+ return 0;
+}
+
+int __vesacon_init(int x, int y)
+{
+ int rv;
+
+ /* We need the FPU for graphics, at least libpng et al will need it... */
+printf("vesacon_init: enter\n");
+ if (x86_init_fpu())
+ return 10;
+
+printf("vesacon_init: set mode\n");
+ rv = vesacon_set_mode(x, y);
+ /* FIXME: Accessing Video BIOS from EFI will probably not work */
+#ifndef SYSLINUX_EFI
+ if (rv) {
+ /* Try to see if we can just patch the BIOS... */
+ if (__vesacon_i915resolution(x, y))
+ return rv;
+ if (vesacon_set_mode(x, y))
+ return rv;
+ }
+#else
+ /* FIXME: Accessing Video BIOS from EFI will probably not work, skip it for now */
+#endif
+
+ init_text_display();
+
+ debug("Mode set, now drawing at %#p\r\n", __vesa_info.mi.lfb_ptr);
+
+ __vesacon_init_background();
+
+ debug("Ready!\r\n");
+ return 0;
+}
diff --git a/com32/lib/sys/vesa/efi/screencpy.c b/com32/lib/sys/vesa/efi/screencpy.c
new file mode 100644
index 00000000..345cdf44
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/screencpy.c
@@ -0,0 +1,169 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <inttypes.h>
+#include <minmax.h>
+#include <klibc/compiler.h>
+#include <string.h>
+#include <com32.h>
+#include <ilog2.h>
+#include "vesa.h"
+#include "video.h"
+
+static struct win_info {
+ char *win_base;
+ size_t win_pos;
+ size_t win_size;
+ int win_gshift;
+ int win_num;
+} wi;
+
+#ifndef SYSLINUX_EFI
+void __vesacon_init_copy_to_screen(void)
+{
+ struct vesa_mode_info *const mi = &__vesa_info.mi;
+ int winn;
+
+ if (mi->mode_attr & 0x0080) {
+ /* Linear frame buffer */
+
+ wi.win_base = (char *)mi->lfb_ptr;
+ wi.win_size = 1 << 31; /* 2 GB, i.e. one huge window */
+ wi.win_pos = 0; /* Already positioned (only one position...) */
+ wi.win_num = -1; /* Not a window */
+ } else {
+ /* Paged frame buffer */
+
+ /* We have already tested that *one* of these is usable */
+ if ((mi->win_attr[0] & 0x05) == 0x05 && mi->win_seg[0])
+ winn = 0;
+ else
+ winn = 1;
+
+ wi.win_num = winn;
+ wi.win_base = (char *)(mi->win_seg[winn] << 4);
+ wi.win_size = mi->win_size << 10;
+ wi.win_gshift = ilog2(mi->win_grain) + 10;
+ wi.win_pos = -1; /* Undefined position */
+ }
+}
+
+static void set_window_pos(size_t win_pos)
+{
+ static com32sys_t ireg;
+
+ wi.win_pos = win_pos;
+
+ if (wi.win_num < 0)
+ return; /* This should never happen... */
+
+ ireg.eax.w[0] = 0x4F05;
+ ireg.ebx.b[0] = wi.win_num;
+ ireg.edx.w[0] = win_pos >> wi.win_gshift;
+
+ __intcall(0x10, &ireg, NULL);
+}
+
+void __vesacon_copy_to_screen(size_t dst, const uint32_t * src, size_t npixels)
+{
+ size_t win_pos, win_off;
+ size_t win_size = wi.win_size;
+ size_t omask = win_size - 1;
+ char *win_base = wi.win_base;
+ size_t l;
+ size_t bytes = npixels * __vesacon_bytes_per_pixel;
+ char rowbuf[bytes + 4] __aligned(4);
+ const char *s;
+
+ s = (const char *)__vesacon_format_pixels(rowbuf, src, npixels);
+
+ while (bytes) {
+ win_off = dst & omask;
+ win_pos = dst & ~omask;
+
+ if (__unlikely(win_pos != wi.win_pos))
+ set_window_pos(win_pos);
+
+ l = min(bytes, win_size - win_off);
+ memcpy(win_base + win_off, s, l);
+
+ bytes -= l;
+ s += l;
+ dst += l;
+ }
+}
+#else
+void __vesacon_init_copy_to_screen(void)
+{
+ struct vesa_mode_info *const mi = &__vesa_info.mi;
+ int winn;
+
+ if (mi->mode_attr & 0x0080) {
+ /* Linear frame buffer */
+
+ wi.win_base = (char *)mi->lfb_ptr;
+ wi.win_size = mi->lfb_line_size*mi->v_res; /* one giant window */
+ wi.win_pos = 0; /* Already positioned (only one position...) */
+ wi.win_num = -1; /* Not a window */
+ }
+ /* FIXME: PixelBltOnly mode is unsupported */
+}
+
+/* FIXME: Nothing to do for EFI */
+static void set_window_pos(size_t win_pos)
+{
+}
+
+void __vesacon_copy_to_screen(size_t dst, const uint32_t * src, size_t npixels)
+{
+ size_t win_pos, win_off;
+ size_t win_size = wi.win_size;
+ size_t omask = win_size - 1;
+ char *win_base = wi.win_base;
+ size_t l;
+ size_t bytes = npixels * __vesacon_bytes_per_pixel;
+ char rowbuf[bytes + 4] __aligned(4);
+ const char *s;
+
+ s = (const char *)__vesacon_format_pixels(rowbuf, src, npixels);
+
+ while (bytes) {
+ win_off = dst & omask;
+ win_pos = dst & ~omask;
+
+ if (__unlikely(win_pos != wi.win_pos))
+ set_window_pos(win_pos);
+
+ l = min(bytes, win_size - win_off);
+ memcpy(win_base + win_off, s, l);
+
+ bytes -= l;
+ s += l;
+ dst += l;
+ }
+}
+#endif /* SYSLINUX_EFI */
diff --git a/com32/lib/sys/vesa/efi/vesa.h b/com32/lib/sys/vesa/efi/vesa.h
new file mode 100644
index 00000000..81583c6b
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/vesa.h
@@ -0,0 +1,129 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef LIB_SYS_VESA_H
+#define LIB_SYS_VESA_H
+
+#include <inttypes.h>
+#include <com32.h>
+
+/* VESA General Information table */
+struct vesa_general_info {
+ uint32_t signature; /* Magic number = "VESA" */
+ uint16_t version;
+ far_ptr_t vendor_string;
+ uint8_t capabilities[4];
+ far_ptr_t video_mode_ptr;
+ uint16_t total_memory;
+
+ uint16_t oem_software_rev;
+ far_ptr_t oem_vendor_name_ptr;
+ far_ptr_t oem_product_name_ptr;
+ far_ptr_t oem_product_rev_ptr;
+
+ uint8_t reserved[222];
+ uint8_t oem_data[256];
+} __attribute__ ((packed));
+
+#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
+#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24))
+
+struct vesa_mode_info {
+ uint16_t mode_attr;
+ uint8_t win_attr[2];
+ uint16_t win_grain;
+ uint16_t win_size;
+ uint16_t win_seg[2];
+ far_ptr_t win_scheme;
+ uint16_t logical_scan;
+
+ uint16_t h_res;
+ uint16_t v_res;
+ uint8_t char_width;
+ uint8_t char_height;
+ uint8_t memory_planes;
+ uint8_t bpp;
+ uint8_t banks;
+ uint8_t memory_layout;
+ uint8_t bank_size;
+ uint8_t image_pages;
+ uint8_t page_function;
+
+ uint8_t rmask;
+ uint8_t rpos;
+ uint8_t gmask;
+ uint8_t gpos;
+ uint8_t bmask;
+ uint8_t bpos;
+ uint8_t resv_mask;
+ uint8_t resv_pos;
+ uint8_t dcm_info;
+
+ uint8_t *lfb_ptr; /* Linear frame buffer address */
+#ifdef SYSLINUX_EFI
+ /* GOP provides info about FrameBufferBase and Size
+ * Are these types consistent with EFI definition?
+ */
+ uint32_t lfb_size; /* frame buffer size */
+ uint16_t lfb_line_size; /* length of a line in bytes in frame buffer */
+ /* the following pixel sizes are relevant only if the
+ * pixel format for the GOP mode is PixelBitMask
+ */
+ uint8_t resv_size;
+ uint8_t lfb_rsize;
+ uint8_t lfb_gsize;
+ uint8_t lfb_bsize;
+ uint8_t lfb_resv_size;
+#endif
+ uint8_t *offscreen_ptr; /* Offscreen memory address */
+ uint16_t offscreen_size;
+
+ uint8_t reserved[206];
+} __attribute__ ((packed));
+
+struct vesa_info {
+ struct vesa_general_info gi;
+ struct vesa_mode_info mi;
+};
+
+extern struct vesa_info __vesa_info;
+
+#if 0
+static inline void vesa_debug(uint32_t color, int pos)
+{
+ uint32_t *stp = (uint32_t *) __vesa_info.mi.lfb_ptr;
+ stp[pos * 3] = color;
+}
+#else
+static inline void vesa_debug(uint32_t color, int pos)
+{
+ (void)color;
+ (void)pos;
+}
+#endif
+
+#endif /* LIB_SYS_VESA_H */
diff --git a/com32/lib/sys/vesa/efi/video.h b/com32/lib/sys/vesa/efi/video.h
new file mode 100644
index 00000000..d14494b1
--- /dev/null
+++ b/com32/lib/sys/vesa/efi/video.h
@@ -0,0 +1,97 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef LIB_SYS_VESA_VIDEO_H
+#define LIB_SYS_VESA_VIDEO_H
+
+#include <stdbool.h>
+#include <colortbl.h>
+#include "vesa.h"
+
+#define FONT_MAX_CHARS 256
+#define FONT_MAX_HEIGHT 32
+#define FONT_WIDTH 8
+
+#define DEFAULT_VESA_X_SIZE 640
+#define DEFAULT_VESA_Y_SIZE 480
+
+#define VIDEO_BORDER 8
+#define TEXT_PIXEL_ROWS (__vesa_info.mi.v_res - 2*VIDEO_BORDER)
+#define TEXT_PIXEL_COLS (__vesa_info.mi.h_res - 2*VIDEO_BORDER)
+
+typedef uint16_t attr_t;
+
+struct vesa_char {
+ uint8_t ch; /* Character */
+ uint8_t _filler; /* Currently unused */
+ attr_t attr; /* Color table index */
+};
+
+/* Pixel formats in order of decreasing preference; PXF_NONE should be last */
+/* BGR24 is preferred over BGRA32 since the I/O overhead is smaller. */
+enum vesa_pixel_format {
+ PXF_BGR24, /* 24-bit BGR */
+ PXF_BGRA32, /* 32-bit BGRA */
+ PXF_LE_RGB16_565, /* 16-bit littleendian 5:6:5 RGB */
+ PXF_LE_RGB15_555, /* 15-bit littleendian 5:5:5 RGB */
+ PXF_NONE
+};
+extern enum vesa_pixel_format __vesacon_pixel_format;
+extern unsigned int __vesacon_bytes_per_pixel;
+typedef const void *(*__vesacon_format_pixels_t)
+ (void *, const uint32_t *, size_t);
+extern __vesacon_format_pixels_t __vesacon_format_pixels;
+extern const __vesacon_format_pixels_t __vesacon_format_pixels_list[PXF_NONE];
+
+extern struct vesa_char *__vesacon_text_display;
+
+extern int __vesacon_font_height;
+extern int __vesacon_text_rows;
+extern int __vesacon_text_cols;
+extern uint8_t __vesacon_graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT];
+extern uint32_t *__vesacon_background;
+extern uint32_t *__vesacon_shadowfb;
+
+extern const uint16_t __vesacon_srgb_to_linear[256];
+extern const uint8_t __vesacon_linear_to_srgb[4080];
+
+int __vesacon_init_background(void);
+int vesacon_load_background(const char *);
+int __vesacon_init(int, int);
+void __vesacon_init_cursor(int);
+void __vesacon_erase(int, int, int, int, attr_t);
+void __vesacon_scroll_up(int, attr_t);
+void __vesacon_write_char(int, int, uint8_t, attr_t);
+void __vesacon_redraw_text(void);
+void __vesacon_doit(void);
+void __vesacon_set_cursor(int, int, bool);
+void __vesacon_copy_to_screen(size_t, const uint32_t *, size_t);
+void __vesacon_init_copy_to_screen(void);
+
+int __vesacon_i915resolution(int x, int y);
+
+#endif /* LIB_SYS_VESA_VIDEO_H */
diff --git a/com32/lib/sys/vesacon_write.c b/com32/lib/sys/vesacon_write.c
index 37693177..c683c60a 100644
--- a/com32/lib/sys/vesacon_write.c
+++ b/com32/lib/sys/vesacon_write.c
@@ -43,7 +43,11 @@
#include <syslinux/config.h>
#include "ansi.h"
#include "file.h"
+#ifndef SYSLINUX_EFI
#include "vesa/video.h"
+#else
+#include "vesa/efi/video.h" /* FIXME: move to video.h */
+#endif
static void vesacon_erase(const struct term_state *, int, int, int, int);
static void vesacon_write_char(int, int, uint8_t, const struct term_state *);
diff --git a/com32/lib/sys/x86_64/x86_init_fpu.c b/com32/lib/sys/x86_64/x86_init_fpu.c
new file mode 100644
index 00000000..c5d3946c
--- /dev/null
+++ b/com32/lib/sys/x86_64/x86_init_fpu.c
@@ -0,0 +1,58 @@
+/*
+ * x86_has_fpu.c
+ *
+ * Test for an x86 FPU, and do any necessary setup.
+ */
+
+#include <inttypes.h>
+#include <sys/fpu.h>
+
+static inline uint64_t get_cr0(void)
+{
+ uint64_t v;
+asm("movq %%cr0,%0":"=r"(v));
+ return v;
+}
+
+static inline void set_cr0(uint32_t v)
+{
+ asm volatile ("movq %0,%%cr0"::"r" ((uint64_t)v));
+}
+
+#define CR0_PE 0x00000001
+#define CR0_MP 0x00000002
+#define CR0_EM 0x00000004
+#define CR0_TS 0x00000008
+#define CR0_ET 0x00000010
+#define CR0_NE 0x00000020
+#define CR0_WP 0x00010000
+#define CR0_AM 0x00040000
+#define CR0_NW 0x20000000
+#define CR0_CD 0x40000000
+#define CR0_PG 0x80000000
+
+int x86_init_fpu(void)
+{
+ uint32_t cr0;
+ uint16_t fsw = 0xffff;
+ uint16_t fcw = 0xffff;
+
+ cr0 = get_cr0();
+ cr0 &= ~(CR0_EM | CR0_TS);
+ cr0 |= CR0_MP;
+ set_cr0(cr0);
+
+ asm volatile ("fninit");
+ asm volatile ("fnstsw %0":"+m" (fsw));
+ if (fsw != 0)
+ return -1;
+
+ asm volatile ("fnstcw %0":"+m" (fcw));
+ if ((fcw & 0x103f) != 0x3f)
+ return -1;
+
+ /* Techically, this could be a 386 with a 287. We could add a check
+ for that here... */
+
+ return 0;
+}
diff --git a/com32/lib/sys/x86_init_fpu.c b/com32/lib/sys/x86_init_fpu.c
index cf336932..cacb4ea3 100644
--- a/com32/lib/sys/x86_init_fpu.c
+++ b/com32/lib/sys/x86_init_fpu.c
@@ -4,19 +4,40 @@
* Test for an x86 FPU, and do any necessary setup.
*/
+#if __SIZEOF_POINTER__ == 4
+#include <i386/x86_init_fpu.c>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/x86_init_fpu.c>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
+#if 0
#include <inttypes.h>
#include <sys/fpu.h>
static inline uint64_t get_cr0(void)
{
+#if __SIZEOF_POINTER__ == 4
uint32_t v;
asm("movl %%cr0,%0":"=r"(v));
+#elif __SIZEOF_POINTER__ == 8
+ uint64_t v;
+asm("movq %%cr0,%0":"=r"(v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
return v;
}
static inline void set_cr0(uint32_t v)
{
+#if __SIZEOF_POINTER__ == 4
asm volatile ("movl %0,%%cr0"::"r" (v));
+#elif __SIZEOF_POINTER__ == 8
+ asm volatile ("movq %0,%%cr0"::"r" ((uint64_t)v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
}
#define CR0_PE 0x00000001
@@ -56,3 +77,4 @@ int x86_init_fpu(void)
return 0;
}
+#endif
diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c
index 066f174f..7d8581e4 100644
--- a/com32/lib/syslinux/cleanup.c
+++ b/com32/lib/syslinux/cleanup.c
@@ -29,8 +29,6 @@
#include <syslinux/config.h>
#include <syslinux/pxe_api.h>
#include <stddef.h>
-#include <bios.h>
-#include <com32.h>
#include <core.h>
void syslinux_final_cleanup(uint16_t flags)
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index c0335dc9..4a8a1fd3 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -47,48 +47,7 @@
#include <syslinux/linux.h>
#include <syslinux/bootrm.h>
#include <syslinux/movebits.h>
-
-struct linux_header {
- uint8_t boot_sector_1[0x0020];
- uint16_t old_cmd_line_magic;
- uint16_t old_cmd_line_offset;
- uint8_t boot_sector_2[0x01f1 - 0x0024];
- uint8_t setup_sects;
- uint16_t root_flags;
- uint32_t syssize;
- uint16_t ram_size;
- uint16_t vid_mode;
- uint16_t root_dev;
- uint16_t boot_flag;
- uint16_t jump;
- uint32_t header;
- uint16_t version;
- uint32_t realmode_swtch;
- uint16_t start_sys;
- uint16_t kernel_version;
- uint8_t type_of_loader;
- uint8_t loadflags;
- uint16_t setup_move_size;
- uint32_t code32_start;
- uint32_t ramdisk_image;
- uint32_t ramdisk_size;
- uint32_t bootsect_kludge;
- uint16_t heap_end_ptr;
- uint16_t pad1;
- uint32_t cmd_line_ptr;
- uint32_t initrd_addr_max;
- uint32_t kernel_alignment;
- uint8_t relocatable_kernel;
- uint8_t pad2[3];
- uint32_t cmdline_max_len;
- uint32_t hardware_subarch;
- uint64_t hardware_subarch_data;
- uint32_t payload_offset;
- uint32_t payload_length;
- uint64_t setup_data;
- uint64_t pref_address;
- uint32_t init_size;
-} __packed;
+#include <syslinux/firmware.h>
#define BOOT_MAGIC 0xAA55
#define LINUX_MAGIC ('H' + ('d' << 8) + ('r' << 16) + ('S' << 24))
@@ -130,23 +89,6 @@ static inline uint32_t saturate32(unsigned long long v)
return (v > 0xffffffff) ? 0xffffffff : (uint32_t) v;
}
-/* Get the combined size of the initramfs */
-static addr_t initramfs_size(struct initramfs *initramfs)
-{
- struct initramfs *ip;
- addr_t size = 0;
-
- if (!initramfs)
- return 0;
-
- for (ip = initramfs->next; ip->len; ip = ip->next) {
- size = (size + ip->align - 1) & ~(ip->align - 1); /* Alignment */
- size += ip->len;
- }
-
- return size;
-}
-
/* Create the appropriate mappings for the initramfs */
static int map_initramfs(struct syslinux_movelist **fraglist,
struct syslinux_memmap **mmap,
@@ -182,10 +124,10 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
return 0;
}
-int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs,
- struct setup_data *setup_data,
- char *cmdline)
+int bios_boot_linux(void *kernel_buf, size_t kernel_size,
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
{
struct linux_header hdr, *whdr;
size_t real_mode_size, prot_mode_size;
@@ -534,3 +476,17 @@ bail:
syslinux_free_memmap(amap);
return -1;
}
+
+int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
+{
+ if (!firmware->boot_linux) {
+ printf("No linux boot function registered for firmware\n");
+ return -1;
+ }
+
+ firmware->boot_linux(kernel_buf, kernel_size, initramfs,
+ setup_data, cmdline);
+}
diff --git a/com32/lib/syslinux/memscan.c b/com32/lib/syslinux/memscan.c
index fc676cbf..ccd0e5cc 100644
--- a/com32/lib/syslinux/memscan.c
+++ b/com32/lib/syslinux/memscan.c
@@ -40,6 +40,7 @@
#include <com32.h>
#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
struct e820_entry {
uint64_t start;
@@ -47,7 +48,7 @@ struct e820_entry {
uint32_t type;
};
-int syslinux_scan_memory(scan_memory_callback_t callback, void *data)
+int bios_scan_memory(scan_memory_callback_t callback, void *data)
{
static com32sys_t ireg;
com32sys_t oreg;
@@ -156,3 +157,8 @@ int syslinux_scan_memory(scan_memory_callback_t callback, void *data)
return 0;
}
+
+int syslinux_scan_memory(scan_memory_callback_t callback, void *data)
+{
+ return firmware->scan_memory(callback, data);
+}
diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c
index bb92222f..bc41acfc 100644
--- a/com32/lib/syslinux/serial.c
+++ b/com32/lib/syslinux/serial.c
@@ -32,24 +32,19 @@
*/
#include <klibc/compiler.h>
+#include <syslinux/firmware.h>
#include <syslinux/config.h>
#include <string.h>
-#include <bios.h>
-#include <core.h>
struct syslinux_serial_console_info __syslinux_serial_console_info;
void __constructor __syslinux_get_serial_console_info(void)
{
- uint16_t flowctl;
+ uint16_t iobase, divisor, flowctl;
- __syslinux_serial_console_info.iobase = SerialPort;
- __syslinux_serial_console_info.divisor = BaudDivisor;
-
- flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
-
- if (!DisplayCon)
- flowctl |= (0x80 << 8);
+ firmware->get_serial_console_info(&iobase, &divisor, &flowctl);
+ __syslinux_serial_console_info.iobase = iobase;
+ __syslinux_serial_console_info.divisor = divisor;
__syslinux_serial_console_info.flowctl = flowctl;
}
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index 544915a3..d014340c 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -50,10 +50,12 @@ struct shuffle_descriptor {
static int shuffler_size;
-static void __constructor __syslinux_get_shuffer_size(void)
+static void __syslinux_get_shuffer_size(void)
{
- /* +15 padding is to guarantee alignment */
- shuffler_size = __bcopyxx_len + 15;
+ if (!shuffler_size) {
+ /* +15 padding is to guarantee alignment */
+ shuffler_size = __bcopyxx_len + 15;
+ }
}
/*
@@ -114,6 +116,7 @@ int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
if (!rxmap)
goto bail;
+ __syslinux_get_shuffer_size();
desc_blocks = (nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
for (;;) {
/* We want (desc_blocks) allocation blocks, plus the terminating
diff --git a/com32/lib/x86_64/elf.ld b/com32/lib/x86_64/elf.ld
new file mode 100644
index 00000000..bf9881f1
--- /dev/null
+++ b/com32/lib/x86_64/elf.ld
@@ -0,0 +1,186 @@
+/*
+ * Linker script for ELF dynamic loaded modules.
+ * This simply mirrors the 32bit linker script with minimal x86_64 changes
+ */
+
+/* Script for --shared -z combreloc: shared library, combine & sort relocs */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0 + SIZEOF_HEADERS;
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+/* mouli: introduce alignment for various segments */
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt); }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ . = ALIGN(4);
+ .preinit_array :
+ {
+ KEEP (*(.preinit_array))
+ }
+ .init_array :
+ {
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ }
+ .fini_array :
+ {
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ }
+
+ .ctors :
+ {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ LONG(0x00000000)
+ __module_init_ptr = .;
+ KEEP (*(.ctors_modinit))
+ LONG(0x00000000)
+ __module_main_ptr = .;
+ KEEP (*(.ctors_modmain))
+ LONG(0x00000000)
+ }
+
+ .dtors :
+ {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ LONG(0x00000000)
+ __module_exit_ptr = .;
+ KEEP (*(.dtors_modexit))
+ LONG(0x00000000)
+ }
+
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) }
+ /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */
+ .got.plt : { *(.got.plt) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ PROVIDE (edata = .);
+ PROVIDE (_edata = .);
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ /*. = ALIGN(. != 0 ? 32 / 8 : 1);*/
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ PROVIDE (_end = .);
+ PROVIDE (end = .);
+ /*. = DATA_SEGMENT_END (.); -> This gives a "invalid assignment to location counter" error */
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.eh_frame) }
+}
diff --git a/com32/lib/x86_64/setjmp.S b/com32/lib/x86_64/setjmp.S
new file mode 100644
index 00000000..45f547b4
--- /dev/null
+++ b/com32/lib/x86_64/setjmp.S
@@ -0,0 +1,54 @@
+#
+# arch/x86_64/setjmp.S
+#
+# setjmp/longjmp for the x86-64 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+# %rbx
+# %rsp (post-return)
+# %rbp
+# %r12
+# %r13
+# %r14
+# %r15
+# <return address>
+#
+
+ .text
+ .align 4
+ .globl setjmp
+ .type setjmp, @function
+setjmp:
+ pop %rsi # Return address, and adjust the stack
+ xorl %eax,%eax # Return value
+ movq %rbx,(%rdi)
+ movq %rsp,8(%rdi) # Post-return %rsp!
+ push %rsi # Make the call/return stack happy
+ movq %rbp,16(%rdi)
+ movq %r12,24(%rdi)
+ movq %r13,32(%rdi)
+ movq %r14,40(%rdi)
+ movq %r15,48(%rdi)
+ movq %rsi,56(%rdi) # Return address
+ ret
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+ movl %esi,%eax # Return value (int)
+ movq (%rdi),%rbx
+ movq 8(%rdi),%rsp
+ movq 16(%rdi),%rbp
+ movq 24(%rdi),%r12
+ movq 32(%rdi),%r13
+ movq 40(%rdi),%r14
+ movq 48(%rdi),%r15
+ jmp *56(%rdi)
+
+ .size longjmp,.-longjmp
diff --git a/com32/menu/Makefile b/com32/menu/Makefile
index b7719456..2096b4c4 100644
--- a/com32/menu/Makefile
+++ b/com32/menu/Makefile
@@ -34,6 +34,12 @@ menu.c32 : menu.o $(COMMONOBJS) $(C_LIBS)
vesamenu.c32 : vesamenu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
+vesamenu.c32: vesamenu.o $(COMMONOBJS) $(C_LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+menu.c32: menu.o $(COMMONOBJS) $(C_LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
tidy dist:
rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
diff --git a/com32/modules/ls.c b/com32/modules/ls.c
index 11c18ae0..47eacdbc 100644
--- a/com32/modules/ls.c
+++ b/com32/modules/ls.c
@@ -172,4 +172,4 @@ int main(int argc, char *argv[])
return rv ? 1 : 0;
}
-
+
diff --git a/com32/modules/zzjson.c b/com32/modules/zzjson.c
index e2516fa1..a126b8f0 100644
--- a/com32/modules/zzjson.c
+++ b/com32/modules/zzjson.c
@@ -21,7 +21,13 @@ static void myerror(void *ehandle, const char *format, ...) {
int main(int argc, char *argv[])
{
+#if 0
+ /* this hangs! */
openconsole(&dev_rawcon_r, &dev_stdcon_w);
+#else
+ /* this works */
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
(void) argc;
(void) argv;
ZZJSON *tmp;
diff --git a/com32/samples/advdump.c b/com32/samples/advdump.c
index 2c786416..83fe8381 100644
--- a/com32/samples/advdump.c
+++ b/com32/samples/advdump.c
@@ -27,7 +27,13 @@ int main(void)
size_t s = syslinux_adv_size();
char buf[256];
+#if 0
+ /* this hangs! */
openconsole(&dev_stdcon_r, &dev_stdcon_w);
+#else
+ /* this works */
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
p = syslinux_adv_ptr();
diff --git a/com32/samples/entrydump.c b/com32/samples/entrydump.c
index d50859f4..56a683e3 100644
--- a/com32/samples/entrydump.c
+++ b/com32/samples/entrydump.c
@@ -36,7 +36,13 @@ int main(void)
const union syslinux_derivative_info *di;
const struct stack_frame *sf;
+#if 0
+ /* this hangs! */
openconsole(&dev_null_r, &dev_stdcon_w);
+#else
+ /* this works */
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
di = syslinux_derivative_info();
diff --git a/com32/samples/hello.c b/com32/samples/hello.c
index 77e93ac7..eef85283 100644
--- a/com32/samples/hello.c
+++ b/com32/samples/hello.c
@@ -24,7 +24,13 @@ int main(int argc, char *argv[])
{
int i;
+#if 0
+ /* this hangs! */
openconsole(&dev_stdcon_r, &dev_stdcon_w);
+#else
+ /* this works */
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
printf("Hello, World!\n");
diff --git a/com32/samples/resolv.c b/com32/samples/resolv.c
index f4a0e52a..8f062d19 100644
--- a/com32/samples/resolv.c
+++ b/com32/samples/resolv.c
@@ -32,7 +32,13 @@ int main(int argc, char *argv[])
{
uint32_t ip;
+#if 0
+ /* this hangs! */
openconsole(&dev_null_r, &dev_stdcon_w);
+#else
+ /* this works */
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
if (argc < 2) {
fputs("Usage: resolv hostname\n", stderr);
diff --git a/com32/samples/serialinfo.c b/com32/samples/serialinfo.c
index 10d02521..2936b4e5 100644
--- a/com32/samples/serialinfo.c
+++ b/com32/samples/serialinfo.c
@@ -25,7 +25,13 @@ int main(void)
{
const struct syslinux_serial_console_info *si;
+#if 0
+ /* this hangs! */
openconsole(&dev_null_r, &dev_stdcon_w);
+#else
+ /* this works */
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
si = syslinux_serial_console_info();
diff --git a/com32/sysdump/cpuid.c b/com32/sysdump/cpuid.c
index e7fc5767..846b5408 100644
--- a/com32/sysdump/cpuid.c
+++ b/com32/sysdump/cpuid.c
@@ -20,10 +20,21 @@ struct cpuid_info {
static void get_cpuid(uint32_t eax, uint32_t ecx, struct cpuid_data *data)
{
+#if __SIZEOF_POINTER__ == 4
asm("pushl %%ebx ; cpuid ; movl %%ebx,%1 ; popl %%ebx"
: "=a" (data->eax), "=r" (data->ebx),
"=c" (data->ecx), "=d" (data->edx)
: "a" (eax), "c" (ecx));
+#elif __SIZEOF_POINTER__ == 8
+ asm volatile("push %%rbx; cpuid; movl %%ebx, %1; pop %%rbx"
+ : "=a" (data->eax),
+ "=b" (data->ebx),
+ "=c" (data->ecx),
+ "=d" (data->edx)
+ : "a" (eax), "c" (ecx));
+#else
+#error "unsupported architecture"
+#endif
}
#define CPUID_CHUNK 128
diff --git a/core/Makefile b/core/Makefile
index a01d83a4..3a1e875a 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -25,7 +25,7 @@ include $(MAKEDIR)/embedded.mk
-include $(topdir)/version.mk
OPTFLAGS =
-INCLUDES = -I./include -I$(com32)/include -I$(com32)/lib
+INCLUDES = -I./include -I$(com32)/include -I$(com32)/include/sys -I$(com32)/lib
# This is very similar to cp437; technically it's for Norway and Denmark,
# but it's unlikely the characters that are different will be used in
@@ -55,7 +55,7 @@ COBJS = $(filter-out rawcon.o plaincon.o,$(COBJ))
LIB = libcom32.a
LIBS = $(LIB) --whole-archive $(com32)/lib/libcom32core.a
LIBDEP = $(filter-out -% %start%,$(LIBS))
-LIBOBJS = $(COBJS) $(SOBJ)
+LIBOBJS = $(COBJS) $(SOBJ)
NASMDEBUG = -g -F dwarf
NASMOPT += $(NASMDEBUG)
@@ -74,7 +74,20 @@ ifndef DATE
DATE := $(shell sh ../gen-id.sh $(VERSION) $(HEXDATE))
endif
-all: $(BTARGET)
+# Set up the NASM and LD options for the architecture
+NASM_ELF = "unknown"
+LD_PIE = "unknown"
+ifeq ($(ARCH),i386)
+ NASM_ELF = elf
+ LD_PIE = -pie
+endif
+ifeq ($(ARCH),x86_64)
+ NASM_ELF = elf64
+ #LD_PIE = --pic-executable
+ LD_PIE =
+endif
+
+all: $(BTARGET) clean
kwdhash.gen: keywords genhash.pl
$(PERL) genhash.pl < keywords > kwdhash.gen
@@ -91,14 +104,15 @@ kwdhash.gen: keywords genhash.pl
$(PREPCORE) $< $@
%.o: %.asm kwdhash.gen ../version.gen
- $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+ $(NASM) -f $(NASM_ELF) $(NASMOPT) -DDATE_STR="'$(DATE)'" \
-DHEXDATE="$(HEXDATE)" \
+ -D$(ARCH) \
-l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
AUXLIBS = libisolinux.a libisolinux-debug.a libldlinux.a libpxelinux.a
-%.elf: %.o $(LIBDEP) syslinux.ld $(AUXLIBS)
- $(LD) $(LDFLAGS) -Bsymbolic -pie -E --hash-style=gnu -T syslinux.ld -M -o $@ $< \
+%.elf: %.o $(LIBDEP) $(ARCH)/syslinux.ld $(AUXLIBS)
+ $(LD) $(LDFLAGS) -Bsymbolic $(LD_PIE) -E --hash-style=gnu -T $(ARCH)/syslinux.ld -M -o $@ $< \
--start-group $(LIBS) lib$(patsubst %.elf,%.a,$@) --end-group \
> $(@:.elf=.map)
$(OBJDUMP) -h $@ > $(@:.elf=.sec)
diff --git a/core/bios.c b/core/bios.c
new file mode 100644
index 00000000..ce6a31c0
--- /dev/null
+++ b/core/bios.c
@@ -0,0 +1,303 @@
+#include <sys/ansi.h>
+#include <sys/io.h>
+#include <fs.h>
+#include <bios.h>
+#include <com32.h>
+#include <graphics.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
+
+struct firmware *firmware = NULL;
+
+extern struct ansi_ops bios_ansi_ops;
+
+#define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
+#define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
+#define BIOS_COLS (*(uint16_t *)0x44A)
+#define BIOS_PAGE (*(uint8_t *)0x462)
+
+static void bios_set_mode(uint16_t mode)
+{
+ syslinux_force_text_mode();
+}
+
+static void bios_get_mode(int *cols, int *rows)
+{
+ *rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
+ *cols = BIOS_COLS;
+}
+
+static uint16_t cursor_type; /* Saved cursor pattern */
+
+static void bios_get_cursor(int *x, int *y)
+{
+ com32sys_t ireg, oreg;
+
+ memset(&ireg, 0, sizeof(ireg));
+
+ ireg.eax.b[1] = 0x03;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ __intcall(0x10, &ireg, &oreg);
+ cursor_type = oreg.ecx.w[0];
+ *x = oreg.edx.b[0];
+ *y = oreg.edx.b[1];
+}
+
+static void bios_erase(int x0, int y0, int x1, int y1, uint8_t attribute)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0600; /* Clear window */
+ ireg.ebx.b[1] = attribute;
+ ireg.ecx.b[0] = x0;
+ ireg.ecx.b[1] = y0;
+ ireg.edx.b[0] = x1;
+ ireg.edx.b[1] = y1;
+ __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_showcursor(const struct term_state *st)
+{
+ static com32sys_t ireg;
+ uint16_t cursor = st->cursor ? cursor_type : 0x2020;
+
+ ireg.eax.b[1] = 0x01;
+ ireg.ecx.w[0] = cursor;
+ __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_set_cursor(int x, int y, bool visible)
+{
+ const int page = BIOS_PAGE;
+ struct curxy xy = BIOS_CURXY[page];
+ static com32sys_t ireg;
+
+ (void)visible;
+
+ if (xy.x != x || xy.y != y) {
+ ireg.eax.b[1] = 0x02;
+ ireg.ebx.b[1] = page;
+ ireg.edx.b[1] = y;
+ ireg.edx.b[0] = x;
+ __intcall(0x10, &ireg, NULL);
+ }
+}
+
+static void bios_write_char(uint8_t ch, uint8_t attribute)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.b[1] = 0x09;
+ ireg.eax.b[0] = ch;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ ireg.ebx.b[0] = attribute;
+ ireg.ecx.w[0] = 1;
+ __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0601;
+ ireg.ebx.b[1] = attribute;
+ ireg.ecx.w[0] = 0;
+ ireg.edx.b[1] = rows;
+ ireg.edx.b[0] = cols;
+ __intcall(0x10, &ireg, NULL); /* Scroll */
+}
+
+static void bios_beep(void)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0e07;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ __intcall(0x10, &ireg, NULL);
+}
+
+struct output_ops bios_output_ops = {
+ .erase = bios_erase,
+ .write_char = bios_write_char,
+ .showcursor = bios_showcursor,
+ .set_cursor = bios_set_cursor,
+ .scroll_up = bios_scroll_up,
+ .beep = bios_beep,
+ .get_mode = bios_get_mode,
+ .set_mode = bios_set_mode,
+ .get_cursor = bios_get_cursor,
+};
+
+extern char bios_getchar(char *);
+extern int bios_pollchar(void);
+
+struct input_ops bios_input_ops = {
+ .getchar = bios_getchar,
+ .pollchar = bios_pollchar,
+};
+
+static const char *syslinux_ipappend_string_list[32];
+bool bios_ipappend_strings(char **list, int *count)
+{
+ static com32sys_t reg;
+ int i;
+
+ reg.eax.w[0] = 0x000f;
+ __intcall(0x22, &reg, &reg);
+
+ if (reg.eflags.l & EFLAGS_CF)
+ return false;
+
+ for (i = 0; i < reg.ecx.w[0]; i++) {
+ syslinux_ipappend_string_list[i] =
+ MK_PTR(reg.es,
+ *(uint16_t *) MK_PTR(reg.es, reg.ebx.w[0] + i * 2));
+ }
+
+ *list = syslinux_ipappend_string_list;
+ *count = reg.ecx.w[0];
+
+ return true;
+}
+
+static void bios_get_serial_console_info(uint16_t *iobase, uint16_t *divisor,
+ uint16_t *flowctl)
+{
+ *iobase = SerialPort;
+ *divisor = BaudDivisor;
+
+ *flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
+
+ if (!DisplayCon)
+ *flowctl |= (0x80 << 8);
+}
+
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+
+void bios_adv_init(void)
+{
+ static com32sys_t reg;
+
+ reg.eax.w[0] = 0x0025;
+ __intcall(0x22, &reg, &reg);
+
+ reg.eax.w[0] = 0x001c;
+ __intcall(0x22, &reg, &reg);
+ __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
+ __syslinux_adv_size = reg.ecx.w[0];
+}
+
+int bios_adv_write(void)
+{
+ static com32sys_t reg;
+
+ reg.eax.w[0] = 0x001d;
+ __intcall(0x22, &reg, &reg);
+ return (reg.eflags.l & EFLAGS_CF) ? -1 : 0;
+}
+
+struct adv_ops bios_adv_ops = {
+ .init = bios_adv_init,
+ .write = bios_adv_write,
+};
+
+static uint32_t min_lowmem_heap = 65536;
+extern char __lowmem_heap[];
+uint8_t KbdFlags; /* Check for keyboard escapes */
+
+static inline void check_escapes(void)
+{
+ com32sys_t ireg, oreg;
+
+ ireg.eax.b[1] = 0x02; /* Check keyboard flags */
+ __intcall(0x16, &ireg, &oreg);
+
+ KbdFlags = oreg.eax.b[0];
+
+ /* Ctrl->skip 386 check */
+ if (oreg.eax.b[0] & 0x04) {
+ /*
+ * Now check that there is sufficient low (DOS) memory
+ *
+ * NOTE: Linux doesn't use all of real_mode_seg, but we use
+ * the same segment for COMBOOT images, which can use all 64K.
+ */
+ uint16_t mem;
+
+ __intcall(0x12, &ireg, &oreg);
+
+ mem = ((uint32_t)__lowmem_heap) + min_lowmem_heap + 1023;
+ mem = mem >> 10;
+
+ if (mem < oreg.eax.w[0]) {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "It appears your computer has only "
+ "%dK of low (\"DOS\") RAM.\n"
+ "This version of Syslinux needs "
+ "%dK to boot. "
+ "If you get this\nmessage in error, "
+ "hold down the Ctrl key while booting, "
+ "and I\nwill take your word for it.\n",
+ oreg.eax.w[0], mem);
+ writestr(buf);
+ kaboom();
+ }
+ }
+}
+
+extern uint32_t BIOS_timer_next;
+extern uint32_t timer_irq;
+static inline void bios_timer_init(void)
+{
+ unsigned long next;
+ uint32_t *hook = (uint32_t *)BIOS_timer_hook;
+
+ next = *hook;
+ BIOS_timer_next = next;
+ *hook = (uint32_t)&timer_irq;
+}
+
+extern uint8_t bios_free_mem;
+extern void printf_init(void);
+
+void bios_init(void)
+{
+ int i;
+
+ /* Initialize timer */
+ bios_timer_init();
+
+ for (i = 0; i < 256; i++)
+ KbdMap[i] = i;
+
+ bios_adjust_screen();
+ printf_init();
+
+ /* Init the memory subsystem */
+ bios_free_mem = (uint16_t *)0x413;
+ mem_init();
+
+ /* CPU-dependent initialization and related checks. */
+ check_escapes();
+}
+
+struct firmware bios_fw = {
+ .init = bios_init,
+ .scan_memory = bios_scan_memory,
+ .adjust_screen = bios_adjust_screen,
+ .cleanup = bios_cleanup_hardware,
+ .disk_init = bios_disk_init,
+ .o_ops = &bios_output_ops,
+ .i_ops = &bios_input_ops,
+ .ipappend_strings = bios_ipappend_strings,
+ .get_serial_console_info = bios_get_serial_console_info,
+ .adv_ops = &bios_adv_ops,
+};
+
+void syslinux_register_bios(void)
+{
+ firmware = &bios_fw;
+}
diff --git a/core/call16.c b/core/call16.c
index 095f814f..0943a721 100644
--- a/core/call16.c
+++ b/core/call16.c
@@ -24,9 +24,17 @@ const com32sys_t zero_regs; /* Common all-zero register set */
static inline uint32_t eflags(void)
{
- uint32_t v;
+ //uint32_t v;
+#if __SIZEOF_POINTER__ == 4
+ uint32_t v;
asm volatile("pushfl ; popl %0" : "=rm" (v));
+#elif __SIZEOF_POINTER__ == 8
+ uint64_t v;
+ asm volatile("pushfq ; pop %0" : "=rm" (v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
return v;
}
diff --git a/core/cleanup.c b/core/cleanup.c
index 7bf1df2e..4abefcd0 100644
--- a/core/cleanup.c
+++ b/core/cleanup.c
@@ -12,9 +12,11 @@
*/
#include <com32.h>
#include <core.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
-extern void timer_cleanup(void);
extern void comboot_cleanup_api(void);
+extern void bios_timer_cleanup(void);
/*
* cleanup.c
@@ -22,12 +24,7 @@ extern void comboot_cleanup_api(void);
* Some final tidying before jumping to a kernel or bootsector
*/
-/*
- * cleanup_hardware:
- *
- * Shut down anything transient.
- */
-void cleanup_hardware(void)
+void bios_cleanup_hardware(void)
{
/*
* TODO
@@ -39,8 +36,18 @@ void cleanup_hardware(void)
__intcall(0x13, &zero_regs, NULL);
call16(comboot_cleanup_api, &zero_regs, NULL);
- call16(timer_cleanup, &zero_regs, NULL);
+ call16(bios_timer_cleanup, &zero_regs, NULL);
/* If we enabled serial port interrupts, clean them up now */
sirq_cleanup();
}
+
+/*
+ * cleanup_hardware:
+ *
+ * Shut down anything transient.
+ */
+void cleanup_hardware(void)
+{
+ firmware->cleanup();
+}
diff --git a/core/conio.c b/core/conio.c
index 421dabfd..d34c9cf2 100644
--- a/core/conio.c
+++ b/core/conio.c
@@ -27,6 +27,7 @@
#include <fs.h>
#include <com32.h>
#include <sys/cpu.h>
+#include <syslinux/firmware.h>
#include "bios.h"
#include "graphics.h"
@@ -117,15 +118,6 @@ int get_msg_file(char *filename)
return 0;
}
-static inline void msg_beep(void)
-{
- com32sys_t ireg, oreg;
-
- ireg.eax.w[0] = 0x0E07; /* Beep */
- ireg.ebx.w[0] = 0x0000;
- __intcall(0x10, &ireg, &oreg);
-}
-
/*
* write_serial: If serial output is enabled, write character on
* serial port.
@@ -162,12 +154,12 @@ void pm_write_serial(com32sys_t *regs)
write_serial(regs->eax.b[0]);
}
-void pm_serialcfg(com32sys_t *regs)
+void serialcfg(uint16_t *iobase, uint16_t *divisor, uint16_t *flowctl)
{
uint8_t al, ah;
- regs->eax.w[0] = SerialPort;
- regs->ecx.w[0] = BaudDivisor;
+ *iobase = SerialPort;
+ *divisor = BaudDivisor;
al = FlowOutput;
ah = FlowInput;
@@ -179,7 +171,12 @@ void pm_serialcfg(com32sys_t *regs)
if (!DisplayCon)
ah |= 0x80;
- regs->ebx.w[0] = al | (ah << 8);
+ *flowctl = al | (ah << 8);
+}
+
+void pm_serialcfg(com32sys_t *regs)
+{
+ serialcfg(&regs->eax.w[0], &regs->ecx.w[0], &regs->ebx.w[0]);
}
static void write_serial_displaymask(char data)
@@ -213,7 +210,7 @@ static void write_serial_str_displaymask(char *data)
*
* Returns 1 if character pending.
*/
-int pollchar(void)
+int bios_pollchar(void)
{
com32sys_t ireg, oreg;
uint8_t data = 0;
@@ -253,6 +250,11 @@ int pollchar(void)
return data;
}
+int pollchar(void)
+{
+ return firmware->i_ops->pollchar();
+}
+
void pm_pollchar(com32sys_t *regs)
{
if (pollchar())
@@ -263,10 +265,7 @@ void pm_pollchar(com32sys_t *regs)
extern void do_idle(void);
-/*
- * getchar: Read a character from keyboard or serial port
- */
-char getchar(char *hi)
+char bios_getchar(char *hi)
{
com32sys_t ireg, oreg;
unsigned char data;
@@ -332,6 +331,14 @@ char getchar(char *hi)
return data;
}
+/*
+ * getchar: Read a character from keyboard or serial port
+ */
+char getchar(char *hi)
+{
+ return firmware->i_ops->getchar(hi);
+}
+
void pm_getchar(com32sys_t *regs)
{
regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
@@ -371,15 +378,7 @@ static inline void msg_ctrl_o(void)
static void msg_gotoxy(void)
{
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
- ireg.edx.w[0] = CursorDX;
- ireg.eax.b[1] = 0x02; /* Set cursor position */
-
- __intcall(0x10, &ireg, &oreg);
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
static void msg_newline(void)
@@ -396,18 +395,11 @@ static void msg_newline(void)
if ((CursorRow + 1) <= VidRows)
CursorRow++;
else {
- ireg.ecx.w[0] = 0x0; /* Upper left hand corner */
- ireg.edx.w[0] = ScreenSize;
-
- CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
-
- ireg.ebx.b[1] = ScrollAttribute;
- ireg.eax.w[0] = 0x0601; /* Scroll up one line */
-
- __intcall(0x10, &ireg, &oreg);
+ CursorRow = VidRows; /* New cursor at the bottom */
+ firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
}
- msg_gotoxy();
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
static void msg_formfeed(void)
@@ -417,19 +409,10 @@ static void msg_formfeed(void)
write_serial_str_displaymask(crff_msg);
if (DisplayMask & UsingVGA) {
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
CursorDX = 0x0; /* Upper left hand corner */
- ireg.edx.w[0] = ScreenSize;
- ireg.ebx.b[1] = TextAttribute;
-
- ireg.eax.w[0] = 0x0600; /* Clear screen region */
- __intcall(0x10, &ireg, &oreg);
-
- msg_gotoxy();
+ firmware->o_ops->erase(0, 0, VidCols, VidRows, TextAttribute);
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
}
@@ -491,22 +474,11 @@ static void msg_line_wrap(void)
if ((CursorRow + 1) <= VidRows)
CursorRow++;
else {
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.ecx.w[0] = 0x0; /* Upper left hand corner */
- ireg.edx.w[0] = ScreenSize;
-
- CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
-
- ireg.ebx.b[1] = ScrollAttribute;
- ireg.eax.w[0] = 0x0601; /* Scroll up one line */
-
- __intcall(0x10, &ireg, &oreg);
+ /* Scroll up one line */
+ firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
}
- msg_gotoxy();
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
static void msg_normal(char data)
@@ -522,20 +494,12 @@ static void msg_normal(char data)
if (!(DisplayCon & 0x01))
return;
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.ebx.b[0] = TextAttribute;
- ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
- ireg.eax.b[0] = data;
- ireg.eax.b[1] = 0x09; /* Write character/attribute */
- ireg.ecx.w[0] = 1; /* One character only */
-
/* Write to screen */
- __intcall(0x10, &ireg, &oreg);
+ firmware->o_ops->write_char(data, TextAttribute);
if ((CursorCol + 1) <= VidCols) {
CursorCol++;
- msg_gotoxy();
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
} else
msg_line_wrap(); /* Screen wraparound */
}
@@ -568,7 +532,8 @@ static void msg_putchar(char ch)
msg_formfeed();
break;
case 0x07: /* <BEL> = beep */
- msg_beep();
+ if (firmware->o_ops->beep)
+ firmware->o_ops->beep();
break;
case 0x19: /* <EM> = return to text mode */
msg_novga();
@@ -589,12 +554,11 @@ static void msg_putchar(char ch)
void msg_initvars(void)
{
com32sys_t ireg, oreg;
+ int x, y;
- ireg.eax.b[1] = 0x3; /* Read cursor position */
- ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
- __intcall(0x10, &ireg, &oreg);
-
- CursorDX = oreg.edx.w[0];
+ firmware->o_ops->get_cursor(&x, &y);
+ CursorCol = x;
+ CursorRow = y;
/* Initialize state machine */
NextCharJump = msg_putchar;
diff --git a/core/diskstart.inc b/core/diskstart.inc
index c8f79366..0c27d577 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -503,7 +503,7 @@ expand_super:
mov si,[bsHeads]
mov di,[bsSecPerTrack]
movzx ebp,word [MaxTransfer]
- pm_call fs_init
+ pm_call pm_fs_init
pm_call load_env32
popad
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index b15cdbbb..e671891b 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -25,11 +25,12 @@
#define LDLINUX "ldlinux.c32"
extern char __dynstr_start[];
-extern char __dynstr_len[], __dynsym_len[];
+extern char __dynstr_end[], __dynsym_end[];
extern char __dynsym_start[];
extern char __got_start[];
-extern Elf32_Dyn __dynamic_start[];
-extern Elf32_Word __gnu_hash_start[];
+extern Elf_Dyn __dynamic_start[];
+extern Elf_Word __gnu_hash_start[];
+extern char __module_start[];
struct elf_module core_module = {
.name = "(core)",
@@ -38,15 +39,12 @@ struct elf_module core_module = {
.dependants = LIST_HEAD_INIT((core_module.dependants)),
.list = LIST_HEAD_INIT((core_module.list)),
.module_addr = (void *)0x0,
- .base_addr = (Elf32_Addr) 0x0,
.ghash_table = __gnu_hash_start,
.str_table = __dynstr_start,
.sym_table = __dynsym_start,
.got = __got_start,
.dyn_table = __dynamic_start,
- .strtable_size = (size_t) __dynstr_len,
- .syment_size = sizeof(Elf32_Sym),
- .symtable_size = (size_t) __dynsym_len
+ .syment_size = sizeof(Elf_Sym),
};
/*
@@ -110,6 +108,7 @@ void load_env32(com32sys_t * regs __unused)
int fd;
char *argv[] = { LDLINUX, NULL };
char realname[FILENAME_MAX];
+ size_t size;
static const char *search_directories[] = {
"/boot/isolinux",
@@ -125,7 +124,7 @@ void load_env32(com32sys_t * regs __unused)
NULL
};
- dprintf("Starting 32 bit elf module subsystem...\n");
+ dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
PATH = malloc(strlen(PATH_DEFAULT) + 1);
if (!PATH) {
@@ -136,6 +135,12 @@ void load_env32(com32sys_t * regs __unused)
strcpy(PATH, PATH_DEFAULT);
PATH[strlen(PATH_DEFAULT)] = '\0';
+ size = (size_t)__dynstr_end - (size_t)__dynstr_start;
+ core_module.strtable_size = size;
+ size = (size_t)__dynsym_end - (size_t)__dynsym_start;
+ core_module.symtable_size = size;
+ core_module.base_addr = (Elf_Addr)__module_start;
+
init_module_subsystem(&core_module);
start_ldlinux(argv);
diff --git a/core/extern.inc b/core/extern.inc
index 3cde2863..078985ee 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -32,7 +32,7 @@
extern mem_init
; fs.c
- extern fs_init, pm_searchdir, getfssec, getfsbytes
+ extern pm_fs_init, pm_searchdir, getfssec, getfsbytes
extern pm_mangle_name, pm_load_config
extern pm_open_file, pm_close_file
extern SectorSize, SectorShift
diff --git a/core/font.c b/core/font.c
index 9e7aa8f2..a0f73332 100644
--- a/core/font.c
+++ b/core/font.c
@@ -88,7 +88,7 @@ fail:
/*
* use_font:
* This routine activates whatever font happens to be in the
- * vgafontbuf, and updates the adjust_screen data.
+ * vgafontbuf, and updates the bios_adjust_screen data.
* Must be called with CS = DS
*/
void use_font(void)
@@ -125,7 +125,7 @@ void use_font(void)
/* 8 pixels/character */
VidCols = ((GXPixCols >> 3) - 1);
- /* No need to call adjust_screen */
+ /* No need to call bios_adjust_screen */
return;
} else {
ireg.eax.w[0] = 0x1110; /* Load into VGA RAM */
@@ -140,16 +140,17 @@ void use_font(void)
ireg.eax.w[0] = 0x1103; /* Select page 0 */
__intcall(0x10, &ireg, NULL);
}
+
}
- adjust_screen();
+ bios_adjust_screen();
}
/*
- * adjust_screen: Set the internal variables associated with the screen size.
+ * bios_adjust_screen: Set the internal variables associated with the screen size.
* This is a subroutine in case we're loading a custom font.
*/
-void adjust_screen(void)
+void bios_adjust_screen(void)
{
com32sys_t ireg, oreg;
volatile uint8_t *vidrows = (volatile uint8_t *)BIOS_vidrows;
@@ -175,7 +176,7 @@ void adjust_screen(void)
void pm_adjust_screen(com32sys_t *regs __unused)
{
- adjust_screen();
+ bios_adjust_screen();
}
void pm_userfont(com32sys_t *regs)
diff --git a/core/fs/diskio.c b/core/fs/diskio.c
index 66838161..9e1f63fd 100644
--- a/core/fs/diskio.c
+++ b/core/fs/diskio.c
@@ -8,287 +8,7 @@
#include <disk.h>
#include <ilog2.h>
-#define RETRY_COUNT 6
-
-static inline sector_t chs_max(const struct disk *disk)
-{
- return (sector_t)disk->secpercyl << 10;
-}
-
-static int chs_rdwr_sectors(struct disk *disk, void *buf,
- sector_t lba, size_t count, bool is_write)
-{
- char *ptr = buf;
- char *tptr;
- size_t chunk, freeseg;
- int sector_shift = disk->sector_shift;
- uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
- uint32_t t;
- uint32_t c, h, s;
- com32sys_t ireg, oreg;
- size_t done = 0;
- size_t bytes;
- int retry;
- uint32_t maxtransfer = disk->maxtransfer;
-
- if (lba + disk->part_start >= chs_max(disk))
- return 0; /* Impossible CHS request */
-
- memset(&ireg, 0, sizeof ireg);
-
- ireg.eax.b[1] = 0x02 + is_write;
- ireg.edx.b[0] = disk->disk_number;
-
- while (count) {
- chunk = count;
- if (chunk > maxtransfer)
- chunk = maxtransfer;
-
- freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
-
- if ((size_t)buf <= 0xf0000 && freeseg) {
- /* Can do a direct load */
- tptr = ptr;
- } else {
- /* Either accessing high memory or we're crossing a 64K line */
- tptr = core_xfer_buf;
- freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
- }
- if (chunk > freeseg)
- chunk = freeseg;
-
- s = xlba % disk->s;
- t = xlba / disk->s;
- h = t % disk->h;
- c = t / disk->h;
-
- if (chunk > (disk->s - s))
- chunk = disk->s - s;
-
- bytes = chunk << sector_shift;
-
- if (tptr != ptr && is_write)
- memcpy(tptr, ptr, bytes);
-
- ireg.eax.b[0] = chunk;
- ireg.ecx.b[1] = c;
- ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
- ireg.edx.b[1] = h;
- ireg.ebx.w[0] = OFFS(tptr);
- ireg.es = SEG(tptr);
-
- retry = RETRY_COUNT;
-
- for (;;) {
- if (c < 1024) {
- dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
- ireg.edx.b[0], chunk, xlba, c, h, s+1,
- ireg.es, ireg.ebx.w[0],
- (ireg.eax.b[1] & 1) ? "<-" : "->",
- ptr);
-
- __intcall(0x13, &ireg, &oreg);
- if (!(oreg.eflags.l & EFLAGS_CF))
- break;
-
- dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);
-
- if (retry--)
- continue;
-
- /*
- * For any starting value, this will always end with
- * ..., 1, 0
- */
- chunk >>= 1;
- if (chunk) {
- maxtransfer = chunk;
- retry = RETRY_COUNT;
- ireg.eax.b[0] = chunk;
- continue;
- }
- }
-
- printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
- oreg.eax.w[0],
- is_write ? "writing" : "reading",
- lba, c, h, s+1);
- return done; /* Failure */
- }
-
- bytes = chunk << sector_shift;
-
- if (tptr != ptr && !is_write)
- memcpy(ptr, tptr, bytes);
-
- /* If we dropped maxtransfer, it eventually worked, so remember it */
- disk->maxtransfer = maxtransfer;
-
- ptr += bytes;
- xlba += chunk;
- count -= chunk;
- done += chunk;
- }
-
- return done;
-}
-
-struct edd_rdwr_packet {
- uint16_t size;
- uint16_t blocks;
- far_ptr_t buf;
- uint64_t lba;
-};
-
-static int edd_rdwr_sectors(struct disk *disk, void *buf,
- sector_t lba, size_t count, bool is_write)
-{
- static __lowmem struct edd_rdwr_packet pkt;
- char *ptr = buf;
- char *tptr;
- size_t chunk, freeseg;
- int sector_shift = disk->sector_shift;
- com32sys_t ireg, oreg, reset;
- size_t done = 0;
- size_t bytes;
- int retry;
- uint32_t maxtransfer = disk->maxtransfer;
-
- memset(&ireg, 0, sizeof ireg);
-
- ireg.eax.b[1] = 0x42 + is_write;
- ireg.edx.b[0] = disk->disk_number;
- ireg.ds = SEG(&pkt);
- ireg.esi.w[0] = OFFS(&pkt);
-
- memset(&reset, 0, sizeof reset);
-
- lba += disk->part_start;
- while (count) {
- chunk = count;
- if (chunk > maxtransfer)
- chunk = maxtransfer;
-
- freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
-
- if ((size_t)ptr <= 0xf0000 && freeseg) {
- /* Can do a direct load */
- tptr = ptr;
- } else {
- /* Either accessing high memory or we're crossing a 64K line */
- tptr = core_xfer_buf;
- freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
- }
- if (chunk > freeseg)
- chunk = freeseg;
-
- bytes = chunk << sector_shift;
-
- if (tptr != ptr && is_write)
- memcpy(tptr, ptr, bytes);
-
- retry = RETRY_COUNT;
-
- for (;;) {
- pkt.size = sizeof pkt;
- pkt.blocks = chunk;
- pkt.buf = FAR_PTR(tptr);
- pkt.lba = lba;
-
- dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n",
- ireg.edx.b[0], pkt.blocks, pkt.lba,
- pkt.buf.seg, pkt.buf.offs,
- (ireg.eax.b[1] & 1) ? "<-" : "->",
- ptr);
-
- __intcall(0x13, &ireg, &oreg);
- if (!(oreg.eflags.l & EFLAGS_CF))
- break;
-
- dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]);
-
- if (retry--)
- continue;
-
- /*
- * Some systems seem to get "stuck" in an error state when
- * using EBIOS. Doesn't happen when using CBIOS, which is
- * good, since some other systems get timeout failures
- * waiting for the floppy disk to spin up.
- */
- __intcall(0x13, &reset, NULL);
-
- /* For any starting value, this will always end with ..., 1, 0 */
- chunk >>= 1;
- if (chunk) {
- maxtransfer = chunk;
- retry = RETRY_COUNT;
- continue;
- }
-
- /*
- * Total failure. There are systems which identify as
- * EDD-capable but aren't; the known such systems return
- * error code AH=1 (invalid function), but let's not
- * assume that for now.
- *
- * Try to fall back to CHS. If the LBA is absurd, the
- * chs_max() test in chs_rdwr_sectors() will catch it.
- */
- done = chs_rdwr_sectors(disk, buf, lba - disk->part_start,
- count, is_write);
- if (done == (count << sector_shift)) {
- /* Successful, assume this is a CHS disk */
- disk->rdwr_sectors = chs_rdwr_sectors;
- return done;
- }
- printf("EDD: Error %04x %s sector %llu\n",
- oreg.eax.w[0],
- is_write ? "writing" : "reading",
- lba);
- return done; /* Failure */
- }
-
- bytes = chunk << sector_shift;
-
- if (tptr != ptr && !is_write)
- memcpy(ptr, tptr, bytes);
-
- /* If we dropped maxtransfer, it eventually worked, so remember it */
- disk->maxtransfer = maxtransfer;
-
- ptr += bytes;
- lba += chunk;
- count -= chunk;
- done += chunk;
- }
- return done;
-}
-
-struct edd_disk_params {
- uint16_t len;
- uint16_t flags;
- uint32_t phys_c;
- uint32_t phys_h;
- uint32_t phys_s;
- uint64_t sectors;
- uint16_t sector_size;
- far_ptr_t dpte;
- uint16_t devpath_key;
- uint8_t devpath_len;
- uint8_t _pad1[3];
- char bus_type[4];
- char if_type[8];
- uint8_t if_path[8];
- uint8_t dev_path[16];
- uint8_t _pad2;
- uint8_t devpath_csum; /* Depends on devpath_len! */
-} __attribute__((packed));
-
-static inline bool is_power_of_2(uint32_t x)
-{
- return !(x & (x-1));
-}
+#include <syslinux/firmware.h>
void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
{
@@ -297,121 +17,17 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0);
}
-
-struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
- uint16_t bsHeads, uint16_t bsSecPerTrack,
- uint32_t MaxTransfer)
-{
- static struct disk disk;
- static __lowmem struct edd_disk_params edd_params;
- com32sys_t ireg, oreg;
- bool ebios;
- int sector_size;
- unsigned int hard_max_transfer;
-
- memset(&ireg, 0, sizeof ireg);
- ireg.edx.b[0] = devno;
-
- if (cdrom) {
- /*
- * The query functions don't work right on some CD-ROM stacks.
- * Known affected systems: ThinkPad T22, T23.
- */
- sector_size = 2048;
- ebios = true;
- hard_max_transfer = 32;
- } else {
- sector_size = 512;
- ebios = false;
- hard_max_transfer = 63;
-
- /* CBIOS parameters */
- disk.h = bsHeads;
- disk.s = bsSecPerTrack;
-
- if ((int8_t)devno < 0) {
- /* Get hard disk geometry from BIOS */
-
- ireg.eax.b[1] = 0x08;
- __intcall(0x13, &ireg, &oreg);
-
- if (!(oreg.eflags.l & EFLAGS_CF)) {
- disk.h = oreg.edx.b[1] + 1;
- disk.s = oreg.ecx.b[0] & 63;
- }
- }
-
- /* Get EBIOS support */
- ireg.eax.b[1] = 0x41;
- ireg.ebx.w[0] = 0x55aa;
- ireg.eflags.b[0] = 0x3; /* CF set */
-
- __intcall(0x13, &ireg, &oreg);
-
- if (!(oreg.eflags.l & EFLAGS_CF) &&
- oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) {
- ebios = true;
- hard_max_transfer = 127;
-
- /* Query EBIOS parameters */
- /* The memset() is needed once this function can be called
- more than once */
- /* memset(&edd_params, 0, sizeof edd_params); */
- edd_params.len = sizeof edd_params;
-
- ireg.eax.b[1] = 0x48;
- ireg.ds = SEG(&edd_params);
- ireg.esi.w[0] = OFFS(&edd_params);
- __intcall(0x13, &ireg, &oreg);
-
- if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
- if (edd_params.len < sizeof edd_params)
- memset((char *)&edd_params + edd_params.len, 0,
- sizeof edd_params - edd_params.len);
-
- if (edd_params.sector_size >= 512 &&
- is_power_of_2(edd_params.sector_size))
- sector_size = edd_params.sector_size;
- }
- }
-
- }
-
- disk.disk_number = devno;
- disk.sector_size = sector_size;
- disk.sector_shift = ilog2(sector_size);
- disk.part_start = part_start;
- disk.secpercyl = disk.h * disk.s;
- disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
-
- if (!MaxTransfer || MaxTransfer > hard_max_transfer)
- MaxTransfer = hard_max_transfer;
-
- disk.maxtransfer = MaxTransfer;
-
- dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
- devno, cdrom, ebios, sector_size, disk.sector_shift,
- part_start, disk.maxtransfer);
-
- return &disk;
-}
-
-
/*
* Initialize the device structure.
*
* NOTE: the disk cache needs to be revamped to support multiple devices...
*/
-struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
- uint16_t bsHeads, uint16_t bsSecPerTrack,
- uint32_t MaxTransfer)
+struct device * device_init(struct disk_private *args)
{
static struct device dev;
static __hugebss char diskcache[128*1024];
- dev.disk = disk_init(devno, cdrom, part_start,
- bsHeads, bsSecPerTrack, MaxTransfer);
-
+ dev.disk = firmware->disk_init(args);
dev.cache_data = diskcache;
dev.cache_size = sizeof diskcache;
diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c
new file mode 100644
index 00000000..52d20172
--- /dev/null
+++ b/core/fs/diskio_bios.c
@@ -0,0 +1,398 @@
+#include <core.h>
+#include <com32.h>
+#include <fs.h>
+#include <ilog2.h>
+
+#define RETRY_COUNT 6
+
+static inline sector_t chs_max(const struct disk *disk)
+{
+ return (sector_t)disk->secpercyl << 10;
+}
+
+struct edd_rdwr_packet {
+ uint16_t size;
+ uint16_t blocks;
+ far_ptr_t buf;
+ uint64_t lba;
+};
+
+struct edd_disk_params {
+ uint16_t len;
+ uint16_t flags;
+ uint32_t phys_c;
+ uint32_t phys_h;
+ uint32_t phys_s;
+ uint64_t sectors;
+ uint16_t sector_size;
+ far_ptr_t dpte;
+ uint16_t devpath_key;
+ uint8_t devpath_len;
+ uint8_t _pad1[3];
+ char bus_type[4];
+ char if_type[8];
+ uint8_t if_path[8];
+ uint8_t dev_path[16];
+ uint8_t _pad2;
+ uint8_t devpath_csum; /* Depends on devpath_len! */
+} __attribute__((packed));
+
+static inline bool is_power_of_2(uint32_t x)
+{
+ return !(x & (x-1));
+}
+
+static int chs_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ char *ptr = buf;
+ char *tptr;
+ size_t chunk, freeseg;
+ int sector_shift = disk->sector_shift;
+ uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
+ uint32_t t;
+ uint32_t c, h, s;
+ com32sys_t ireg, oreg;
+ size_t done = 0;
+ size_t bytes;
+ int retry;
+ uint32_t maxtransfer = disk->maxtransfer;
+
+ if (lba + disk->part_start >= chs_max(disk))
+ return 0; /* Impossible CHS request */
+
+ memset(&ireg, 0, sizeof ireg);
+
+ ireg.eax.b[1] = 0x02 + is_write;
+ ireg.edx.b[0] = disk->disk_number;
+
+ while (count) {
+ chunk = count;
+ if (chunk > maxtransfer)
+ chunk = maxtransfer;
+
+ freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+ if ((size_t)buf <= 0xf0000 && freeseg) {
+ /* Can do a direct load */
+ tptr = ptr;
+ } else {
+ /* Either accessing high memory or we're crossing a 64K line */
+ tptr = core_xfer_buf;
+ freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+ }
+ if (chunk > freeseg)
+ chunk = freeseg;
+
+ s = xlba % disk->s;
+ t = xlba / disk->s;
+ h = t % disk->h;
+ c = t / disk->h;
+
+ if (chunk > (disk->s - s))
+ chunk = disk->s - s;
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && is_write)
+ memcpy(tptr, ptr, bytes);
+
+ ireg.eax.b[0] = chunk;
+ ireg.ecx.b[1] = c;
+ ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+ ireg.edx.b[1] = h;
+ ireg.ebx.w[0] = OFFS(tptr);
+ ireg.es = SEG(tptr);
+
+ retry = RETRY_COUNT;
+
+ for (;;) {
+ if (c < 1024) {
+ dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
+ ireg.edx.b[0], chunk, xlba, c, h, s+1,
+ ireg.es, ireg.ebx.w[0],
+ (ireg.eax.b[1] & 1) ? "<-" : "->",
+ ptr);
+
+ __intcall(0x13, &ireg, &oreg);
+ if (!(oreg.eflags.l & EFLAGS_CF))
+ break;
+
+ dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);
+
+ if (retry--)
+ continue;
+
+ /*
+ * For any starting value, this will always end with
+ * ..., 1, 0
+ */
+ chunk >>= 1;
+ if (chunk) {
+ maxtransfer = chunk;
+ retry = RETRY_COUNT;
+ ireg.eax.b[0] = chunk;
+ continue;
+ }
+ }
+
+ printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
+ oreg.eax.w[0],
+ is_write ? "writing" : "reading",
+ lba, c, h, s+1);
+ return done; /* Failure */
+ }
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && !is_write)
+ memcpy(ptr, tptr, bytes);
+
+ /* If we dropped maxtransfer, it eventually worked, so remember it */
+ disk->maxtransfer = maxtransfer;
+
+ ptr += bytes;
+ xlba += chunk;
+ count -= chunk;
+ done += chunk;
+ }
+
+ return done;
+}
+
+static int edd_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ static __lowmem struct edd_rdwr_packet pkt;
+ char *ptr = buf;
+ char *tptr;
+ size_t chunk, freeseg;
+ int sector_shift = disk->sector_shift;
+ com32sys_t ireg, oreg, reset;
+ size_t done = 0;
+ size_t bytes;
+ int retry;
+ uint32_t maxtransfer = disk->maxtransfer;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ ireg.eax.b[1] = 0x42 + is_write;
+ ireg.edx.b[0] = disk->disk_number;
+ ireg.ds = SEG(&pkt);
+ ireg.esi.w[0] = OFFS(&pkt);
+
+ memset(&reset, 0, sizeof reset);
+
+ lba += disk->part_start;
+ while (count) {
+ chunk = count;
+ if (chunk > maxtransfer)
+ chunk = maxtransfer;
+
+ freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+ if ((size_t)ptr <= 0xf0000 && freeseg) {
+ /* Can do a direct load */
+ tptr = ptr;
+ } else {
+ /* Either accessing high memory or we're crossing a 64K line */
+ tptr = core_xfer_buf;
+ freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+ }
+ if (chunk > freeseg)
+ chunk = freeseg;
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && is_write)
+ memcpy(tptr, ptr, bytes);
+
+ retry = RETRY_COUNT;
+
+ for (;;) {
+ pkt.size = sizeof pkt;
+ pkt.blocks = chunk;
+ pkt.buf = FAR_PTR(tptr);
+ pkt.lba = lba;
+
+ dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n",
+ ireg.edx.b[0], pkt.blocks, pkt.lba,
+ pkt.buf.seg, pkt.buf.offs,
+ (ireg.eax.b[1] & 1) ? "<-" : "->",
+ ptr);
+
+ __intcall(0x13, &ireg, &oreg);
+ if (!(oreg.eflags.l & EFLAGS_CF))
+ break;
+
+ dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]);
+
+ if (retry--)
+ continue;
+
+ /*
+ * Some systems seem to get "stuck" in an error state when
+ * using EBIOS. Doesn't happen when using CBIOS, which is
+ * good, since some other systems get timeout failures
+ * waiting for the floppy disk to spin up.
+ */
+ __intcall(0x13, &reset, NULL);
+
+ /* For any starting value, this will always end with ..., 1, 0 */
+ chunk >>= 1;
+ if (chunk) {
+ maxtransfer = chunk;
+ retry = RETRY_COUNT;
+ continue;
+ }
+
+ /*
+ * Total failure. There are systems which identify as
+ * EDD-capable but aren't; the known such systems return
+ * error code AH=1 (invalid function), but let's not
+ * assume that for now.
+ *
+ * Try to fall back to CHS. If the LBA is absurd, the
+ * chs_max() test in chs_rdwr_sectors() will catch it.
+ */
+ done = chs_rdwr_sectors(disk, buf, lba - disk->part_start,
+ count, is_write);
+ if (done == (count << sector_shift)) {
+ /* Successful, assume this is a CHS disk */
+ disk->rdwr_sectors = chs_rdwr_sectors;
+ return done;
+ }
+ printf("EDD: Error %04x %s sector %llu\n",
+ oreg.eax.w[0],
+ is_write ? "writing" : "reading",
+ lba);
+ return done; /* Failure */
+ }
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && !is_write)
+ memcpy(ptr, tptr, bytes);
+
+ /* If we dropped maxtransfer, it eventually worked, so remember it */
+ disk->maxtransfer = maxtransfer;
+
+ ptr += bytes;
+ lba += chunk;
+ count -= chunk;
+ done += chunk;
+ }
+ return done;
+}
+
+struct disk *bios_disk_init(struct disk_private *priv)
+{
+ static struct disk disk;
+ com32sys_t *regs = priv->regs;
+ static __lowmem struct edd_disk_params edd_params;
+ com32sys_t ireg, oreg;
+ uint8_t devno = regs->edx.b[0];
+ bool cdrom = regs->edx.b[1];
+ sector_t part_start = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
+ uint16_t bsHeads = regs->esi.w[0];
+ uint16_t bsSecPerTrack = regs->edi.w[0];
+ uint32_t MaxTransfer = regs->ebp.l;
+ bool ebios;
+ int sector_size;
+ unsigned int hard_max_transfer;
+
+ memset(&ireg, 0, sizeof ireg);
+ ireg.edx.b[0] = devno;
+
+ if (cdrom) {
+ /*
+ * The query functions don't work right on some CD-ROM stacks.
+ * Known affected systems: ThinkPad T22, T23.
+ */
+ sector_size = 2048;
+ ebios = true;
+ hard_max_transfer = 32;
+ } else {
+ sector_size = 512;
+ ebios = false;
+ hard_max_transfer = 63;
+
+ /* CBIOS parameters */
+ disk.h = bsHeads;
+ disk.s = bsSecPerTrack;
+
+ if ((int8_t)devno < 0) {
+ /* Get hard disk geometry from BIOS */
+
+ ireg.eax.b[1] = 0x08;
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF)) {
+ disk.h = oreg.edx.b[1] + 1;
+ disk.s = oreg.ecx.b[0] & 63;
+ }
+ }
+
+ /* Get EBIOS support */
+ ireg.eax.b[1] = 0x41;
+ ireg.ebx.w[0] = 0x55aa;
+ ireg.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) &&
+ oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) {
+ ebios = true;
+ hard_max_transfer = 127;
+
+ /* Query EBIOS parameters */
+ /* The memset() is needed once this function can be called
+ more than once */
+ /* memset(&edd_params, 0, sizeof edd_params); */
+ edd_params.len = sizeof edd_params;
+
+ ireg.eax.b[1] = 0x48;
+ ireg.ds = SEG(&edd_params);
+ ireg.esi.w[0] = OFFS(&edd_params);
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
+ if (edd_params.len < sizeof edd_params)
+ memset((char *)&edd_params + edd_params.len, 0,
+ sizeof edd_params - edd_params.len);
+
+ if (edd_params.sector_size >= 512 &&
+ is_power_of_2(edd_params.sector_size))
+ sector_size = edd_params.sector_size;
+ }
+ }
+
+ }
+
+ disk.disk_number = devno;
+ disk.sector_size = sector_size;
+ disk.sector_shift = ilog2(sector_size);
+ disk.part_start = part_start;
+ disk.secpercyl = disk.h * disk.s;
+ disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
+
+ if (!MaxTransfer || MaxTransfer > hard_max_transfer)
+ MaxTransfer = hard_max_transfer;
+
+ disk.maxtransfer = MaxTransfer;
+
+ dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+ devno, cdrom, ebios, sector_size, disk.sector_shift,
+ part_start, disk.maxtransfer);
+
+ disk.private = priv;
+ return &disk;
+}
+
+void pm_fs_init(com32sys_t *regs)
+{
+ static struct disk_private priv;
+
+ priv.regs = regs;
+ fs_init((const struct fs_ops **)regs->eax.l, &priv);
+}
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 7b0f6cea..d8abaa69 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -441,22 +441,16 @@ void pm_close_file(com32sys_t *regs)
* invoke the fs-specific init function;
* initialize the cache if we need one;
* finally, get the current inode for relative path looking.
+ *
+ * ops is a ptr list for several fs_ops
*/
__bss16 uint16_t SectorSize, SectorShift;
-void fs_init(com32sys_t *regs)
+void fs_init(const struct fs_ops **ops, struct disk_private *priv)
{
static struct fs_info fs; /* The actual filesystem buffer */
- uint8_t disk_devno = regs->edx.b[0];
- uint8_t disk_cdrom = regs->edx.b[1];
- sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
- uint16_t disk_heads = regs->esi.w[0];
- uint16_t disk_sectors = regs->edi.w[0];
- uint32_t maxtransfer = regs->ebp.l;
int blk_shift = -1;
struct device *dev = NULL;
- /* ops is a ptr list for several fs_ops */
- const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
/* Initialize malloc() */
mem_init();
@@ -476,8 +470,7 @@ void fs_init(com32sys_t *regs)
fs.fs_dev = NULL;
} else {
if (!dev)
- dev = device_init(disk_devno, disk_cdrom, disk_offset,
- disk_heads, disk_sectors, maxtransfer);
+ dev = device_init(priv);
fs.fs_dev = dev;
}
/* invoke the fs-specific init code */
diff --git a/core/graphics.c b/core/graphics.c
index bdf48a85..e9fea617 100644
--- a/core/graphics.c
+++ b/core/graphics.c
@@ -363,7 +363,7 @@ void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
GXPixRows = pix_rows;
if (!(UsingVGA & 0x08))
- adjust_screen();
+ bios_adjust_screen();
}
void pm_using_vga(com32sys_t *regs)
diff --git a/core/i386/syslinux.ld b/core/i386/syslinux.ld
new file mode 100644
index 00000000..7b4e012c
--- /dev/null
+++ b/core/i386/syslinux.ld
@@ -0,0 +1,428 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+
+STACK32_LEN = 65536;
+
+SECTIONS
+{
+ /* Prefix structure for the compression program */
+ . = 0;
+ __module_start = .;
+ .prefix : {
+ *(.prefix)
+ }
+
+ /* "Early" sections (before the load) */
+ . = 0x1000;
+
+ .earlybss (NOLOAD) : {
+ __earlybss_start = .;
+ *(.earlybss)
+ __earlybss_end = .;
+ }
+ __earlybss_len = ABSOLUTE(__earlybss_end) - ABSOLUTE(__earlybss_start);
+ __earlybss_dwords = (__earlybss_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .bss16 (NOLOAD) : {
+ __bss16_start = .;
+ *(.bss16)
+ __bss16_end = .;
+ }
+ __bss16_len = ABSOLUTE(__bss16_end) - ABSOLUTE(__bss16_start);
+ __bss16_dwords = (__bss16_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .config : AT (__config_lma) {
+ __config_start = .;
+ *(.config)
+ __config_end = .;
+ }
+ __config_len = ABSOLUTE(__config_end) - ABSOLUTE(__config_start);
+ __config_dwords = (__config_len + 3) >> 2;
+
+ /* Generated and/or copied code */
+
+ . = ALIGN(128); /* Minimum separation from mutable data */
+ .replacestub : AT (__replacestub_lma) {
+ __replacestub_start = .;
+ *(.replacestub)
+ __replacestub_end = .;
+ }
+ __replacestub_len = ABSOLUTE(__replacestub_end) - ABSOLUTE(__replacestub_start);
+ __replacestub_dwords = (__replacestub_len + 3) >> 2;
+
+ . = ALIGN(16);
+ __gentextnr_lma = .;
+ .gentextnr : AT(__gentextnr_lma) {
+ __gentextnr_start = .;
+ *(.gentextnr)
+ __gentextnr_end = .;
+ }
+ __gentextnr_len = ABSOLUTE(__gentextnr_end) - ABSOLUTE(__gentextnr_start);
+ __gentextnr_dwords = (__gentextnr_len + 3) >> 2;
+
+ . = STACK_BASE;
+ .stack16 : AT(STACK_BASE) {
+ __stack16_start = .;
+ . += STACK_LEN;
+ __stack16_end = .;
+ }
+ __stack16_len = ABSOLUTE(__stack16_end) - ABSOLUTE(__stack16_start);
+ __stack16_dwords = (__stack16_len + 3) >> 2;
+
+ /* Initialized sections */
+
+ . = 0x7c00;
+ .init : {
+ FILL(0x90909090)
+ __init_start = .;
+ *(.init)
+ __init_end = .;
+ }
+ __init_len = ABSOLUTE(__init_end) - ABSOLUTE(__init_start);
+ __init_dwords = (__init_len + 3) >> 2;
+
+ .text16 : {
+ FILL(0x90909090)
+ __text16_start = .;
+ *(.text16)
+ __text16_end = .;
+ }
+ __text16_len = ABSOLUTE(__text16_end) - ABSOLUTE(__text16_start);
+ __text16_dwords = (__text16_len + 3) >> 2;
+
+ /*
+ * .textnr is used for 32-bit code that is used on the code
+ * path to initialize the .text segment
+ */
+ . = ALIGN(16);
+ .textnr : {
+ FILL(0x90909090)
+ __textnr_start = .;
+ *(.textnr)
+ __textnr_end = .;
+ }
+ __textnr_len = ABSOLUTE(__textnr_end) - ABSOLUTE(__textnr_start);
+ __textnr_dwords = (__textnr_len + 3) >> 2;
+
+ . = ALIGN(16);
+ __bcopyxx_start = .;
+
+ .bcopyxx.text : {
+ FILL(0x90909090)
+ __bcopyxx_text_start = .;
+ *(.bcopyxx.text)
+ __bcopyxx_text_end = .;
+ }
+ __bcopyxx_text_len = ABSOLUTE(__bcopyxx_text_end) - ABSOLUTE(__bcopyxx_text_start);
+ __bcopyxx_text_dwords = (__bcopyxx_text_len + 3) >> 2;
+
+ .bcopyxx.data : {
+ __bcopyxx_data_start = .;
+ *(.bcopyxx.text)
+ __bcopyxx_data_end = .;
+ }
+ __bcopyxx_data_len = ABSOLUTE(__bcopyxx_data_end) - ABSOLUTE(__bcopyxx_data_start);
+ __bcopyxx_data_dwords = (__bcopyxx_data_len + 3) >> 2;
+
+ __bcopyxx_end = .;
+ __bcopyxx_len = ABSOLUTE(__bcopyxx_end) - ABSOLUTE(__bcopyxx_start);
+ __bcopyxx_dwords = (__bcopyxx_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .data16 : {
+ __data16_start = .;
+ *(.data16)
+ __data16_end = .;
+ }
+ __data16_len = ABSOLUTE(__data16_end) - ABSOLUTE(__data16_start);
+ __data16_dwords = (__data16_len + 3) >> 2;
+
+ . = ALIGN(4);
+ __config_lma = .;
+ . += SIZEOF(.config);
+
+ . = ALIGN(4);
+ __replacestub_lma = .;
+ . += SIZEOF(.replacestub);
+
+ /* The 32-bit code loads above the non-progbits sections */
+
+ . = ALIGN(16);
+ __pm_code_lma = .;
+
+ __high_clear_start = .;
+
+ . = ALIGN(512);
+ .adv (NOLOAD) : {
+ __adv_start = .;
+ *(.adv)
+ __adv_end = .;
+ }
+ __adv_len = ABSOLUTE(__adv_end) - ABSOLUTE(__adv_start);
+ __adv_dwords = (__adv_len + 3) >> 2;
+
+ /* Late uninitialized sections */
+
+ . = ALIGN(4);
+ .uibss (NOLOAD) : {
+ __uibss_start = .;
+ *(.uibss)
+ __uibss_end = .;
+ }
+ __uibss_len = ABSOLUTE(__uibss_end) - ABSOLUTE(__uibss_start);
+ __uibss_dwords = (__uibss_len + 3) >> 2;
+
+ _end16 = .;
+ __assert_end16 = ASSERT(_end16 <= 0x10000, "64K overflow");
+
+ /*
+ * Special 16-bit segments
+ */
+
+ . = ALIGN(65536);
+ .real_mode (NOLOAD) : {
+ *(.real_mode)
+ }
+ real_mode_seg = core_real_mode >> 4;
+
+ . = ALIGN(65536);
+ .xfer_buf (NOLOAD) : {
+ *(.xfer_buf)
+ }
+ xfer_buf_seg = core_xfer_buf >> 4;
+
+ /*
+ * The auxilliary data segment is used by the 16-bit code
+ * for items that don't need to live in the bottom 64K.
+ */
+
+ . = ALIGN(16);
+ .auxseg (NOLOAD) : {
+ __auxseg_start = .;
+ *(.auxseg)
+ __auxseg_end = .;
+ }
+ __auxseg_len = ABSOLUTE(__auxseg_end) - ABSOLUTE(__auxseg_start);
+ __auxseg_dwords = (__auxseg_len + 3) >> 2;
+ aux_seg = __auxseg_start >> 4;
+
+ /*
+ * Used to allocate lowmem buffers from 32-bit code
+ */
+ .lowmem (NOLOAD) : {
+ __lowmem_start = .;
+ *(.lowmem)
+ __lowmem_end = .;
+ }
+ __lowmem_len = ABSOLUTE(__lowmem_end) - ABSOLUTE(__lowmem_start);
+ __lowmem_dwords = (__lowmem_len + 3) >> 2;
+
+ __high_clear_end = .;
+
+ __high_clear_len = ABSOLUTE(__high_clear_end) - ABSOLUTE(__high_clear_start);
+ __high_clear_dwords = (__high_clear_len + 3) >> 2;
+
+ /* Start of the lowmem heap */
+ . = ALIGN(16);
+ __lowmem_heap = .;
+
+ /*
+ * 32-bit code. This is a hack for the moment due to the
+ * real-mode segments also allocated.
+ */
+
+ . = 0x100000;
+
+ __pm_code_start = .;
+
+ __text_vma = .;
+ __text_lma = __pm_code_lma;
+ .text : AT(__text_lma) {
+ FILL(0x90909090)
+ __text_start = .;
+ *(.text)
+ *(.text.*)
+ __text_end = .;
+ }
+
+ . = ALIGN(16);
+
+ __rodata_vma = .;
+ __rodata_lma = __rodata_vma + __text_lma - __text_vma;
+ .rodata : AT(__rodata_lma) {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ __rodata_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __ctors_vma = .;
+ __ctors_lma = __ctors_vma + __text_lma - __text_vma;
+ .ctors : AT(__ctors_lma) {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctors_end = .;
+ }
+
+ __dtors_vma = .;
+ __dtors_lma = __dtors_vma + __text_lma - __text_vma;
+ .dtors : AT(__dtors_lma) {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __dtors_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __dynsym_vma = .;
+ __dynsym_lma = __dynsym_vma + __text_lma - __text_vma;
+ .dynsym : AT(__dynsym_lma) {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+ __dynsym_len = __dynsym_end - __dynsym_start;
+
+ . = ALIGN(4);
+
+ __dynstr_vma = .;
+ __dynstr_lma = __dynstr_vma + __text_lma - __text_vma;
+ .dynstr : AT(__dynstr_lma) {
+ __dynstr_start = .;
+ *(.dynstr)
+ __dynstr_end = .;
+ }
+ __dynstr_len = __dynstr_end - __dynstr_start;
+
+ . = ALIGN(4);
+
+ __gnu_hash_vma = .;
+ __gnu_hash_lma = __gnu_hash_vma + __text_lma - __text_vma;
+ .gnu.hash : AT(__gnu_hash_lma) {
+ __gnu_hash_start = .;
+ *(.gnu.hash)
+ __gnu_hash_end = .;
+ }
+
+
+ . = ALIGN(4);
+
+ __dynlink_vma = .;
+ __dynlink_lma = __dynlink_vma + __text_lma - __text_vma;
+ .dynlink : AT(__dynlink_lma) {
+ __dynlink_start = .;
+ *(.dynlink)
+ __dynlink_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __got_vma = .;
+ __got_lma = __got_vma + __text_lma - __text_vma;
+ .got : AT(__got_lma) {
+ __got_start = .;
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __dynamic_vma = .;
+ __dynamic_lma = __dynamic_vma + __text_lma - __text_vma;
+ .dynamic : AT(__dynamic_lma) {
+ __dynamic_start = .;
+ *(.dynamic)
+ __dynamic_end = .;
+ }
+
+ . = ALIGN(16);
+
+ __data_vma = .;
+ __data_lma = __data_vma + __text_lma - __text_vma;
+ .data : AT(__data_lma) {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ __data_end = .;
+ }
+
+ __pm_code_end = .;
+ __pm_code_len = ABSOLUTE(__pm_code_end) - ABSOLUTE(__pm_code_start);
+ __pm_code_dwords = (__pm_code_len + 3) >> 2;
+
+ . = ALIGN(128);
+
+ __bss_vma = .;
+ __bss_lma = .; /* Dummy */
+ .bss (NOLOAD) : AT (__bss_lma) {
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ __bss_end = .;
+ }
+ __bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+ __bss_dwords = (__bss_len + 3) >> 2;
+
+ /* Very large objects which don't need to be zeroed */
+
+ __hugebss_vma = .;
+ __hugebss_lma = .; /* Dummy */
+ .hugebss (NOLOAD) : AT (__hugebss_lma) {
+ __hugebss_start = .;
+ *(.hugebss)
+ *(.hugebss.*)
+ __hugebss_end = .;
+ }
+ __hugebss_len = ABSOLUTE(__hugebss_end) - ABSOLUTE(__hugebss_start);
+ __hugebss_dwords = (__hugebss_len + 3) >> 2;
+
+
+ /* XXX: This stack should be unified with the COM32 stack */
+ __stack_vma = .;
+ __stack_lma = .; /* Dummy */
+ .stack (NOLOAD) : AT(__stack_lma) {
+ __stack_start = .;
+ *(.stack)
+ __stack_end = .;
+ }
+ __stack_len = ABSOLUTE(__stack_end) - ABSOLUTE(__stack_start);
+ __stack_dwords = (__stack_len + 3) >> 2;
+
+ _end = .;
+
+ /* COM32R and kernels are loaded after our own PM code */
+ . = ALIGN(65536);
+ free_high_memory = .;
+
+ /* Stuff we don't need... */
+ /DISCARD/ : {
+ *(.eh_frame)
+ }
+}
diff --git a/core/include/bios.h b/core/include/bios.h
index 42a9768c..49a75f5a 100644
--- a/core/include/bios.h
+++ b/core/include/bios.h
@@ -44,12 +44,6 @@ static inline void io_delay(void)
outb(0x0, IO_DELAY_PORT);
}
-/* conio.c */
-extern unsigned short SerialPort;
-extern unsigned char FlowIgnore;
-extern uint8_t ScrollAttribute;
-extern uint16_t DisplayCon;
-
/*
* Sometimes we need to access screen coordinates as separate 8-bit
* entities and sometimes we need to use them as 16-bit entities. Using
diff --git a/core/include/core.h b/core/include/core.h
index da94dbf4..c665d790 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -11,6 +11,12 @@
#include <com32.h>
#include <errno.h>
#include <syslinux/pmapi.h>
+#ifdef SYSLINUX_EFI
+#include <efi.h>
+#include <efilib.h>
+#undef DEBUG
+#include <efistdarg.h>
+#endif
extern char core_xfer_buf[65536];
extern char core_cache_buf[65536];
@@ -38,6 +44,9 @@ extern uint8_t FlowOutput;
extern uint8_t FlowInput;
extern uint8_t FlowIgnore;
+extern uint8_t ScrollAttribute;
+extern uint16_t DisplayCon;
+
/* diskstart.inc isolinux.asm*/
extern void getlinsec(void);
diff --git a/core/include/disk.h b/core/include/disk.h
index ac23e921..2aec11ce 100644
--- a/core/include/disk.h
+++ b/core/include/disk.h
@@ -4,15 +4,29 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
+#include <core.h>
typedef uint64_t sector_t;
typedef uint64_t block_t;
+#ifdef SYSLINUX_EFI
+struct disk_private {
+ EFI_HANDLE dev_handle;
+ EFI_BLOCK_IO *bio;
+ EFI_DISK_IO *dio;
+};
+#else
+struct disk_private {
+ com32sys_t *regs;
+};
+#endif
+
/*
* struct disk: contains the information about a specific disk and also
* contains the I/O function.
*/
struct disk {
+ struct disk_private *private; /* Firmware-private disk info */
unsigned int disk_number; /* in BIOS style */
unsigned int sector_size; /* gener512B or 2048B */
unsigned int sector_shift;
@@ -31,7 +45,7 @@ extern void read_sectors(char *, sector_t, int);
extern void getoneblk(struct disk *, char *, block_t, int);
/* diskio.c */
-struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
-struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
+struct disk *bios_disk_init(struct disk_private *);
+struct device *device_init(struct disk_private *);
#endif /* DISK_H */
diff --git a/core/include/fs.h b/core/include/fs.h
index 26b99c2d..673be38e 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -186,6 +186,7 @@ static inline struct file *handle_to_file(uint16_t handle)
extern char *PATH;
/* fs.c */
+void fs_init(const struct fs_ops **ops, struct disk_private *priv);
void pm_mangle_name(com32sys_t *);
void pm_searchdir(com32sys_t *);
void mangle_name(char *, const char *);
diff --git a/core/init.c b/core/init.c
index 01319f49..45a05093 100644
--- a/core/init.c
+++ b/core/init.c
@@ -3,82 +3,10 @@
#include <sys/io.h>
#include <fs.h>
#include <bios.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
-static uint32_t min_lowmem_heap = 65536;
-extern char __lowmem_heap[];
-uint8_t KbdFlags; /* Check for keyboard escapes */
-
-static inline void check_escapes(void)
-{
- com32sys_t ireg, oreg;
-
- ireg.eax.b[1] = 0x02; /* Check keyboard flags */
- __intcall(0x16, &ireg, &oreg);
-
- KbdFlags = oreg.eax.b[0];
-
- /* Ctrl->skip 386 check */
- if (oreg.eax.b[0] & 0x04) {
- /*
- * Now check that there is sufficient low (DOS) memory
- *
- * NOTE: Linux doesn't use all of real_mode_seg, but we use
- * the same segment for COMBOOT images, which can use all 64K.
- */
- uint16_t mem;
-
- __intcall(0x12, &ireg, &oreg);
-
- mem = ((uint32_t)__lowmem_heap) + min_lowmem_heap + 1023;
- mem = mem >> 10;
-
- if (mem < oreg.eax.w[0]) {
- char buf[256];
-
- snprintf(buf, sizeof(buf),
- "It appears your computer has only "
- "%dK of low (\"DOS\") RAM.\n"
- "This version of Syslinux needs "
- "%dK to boot. "
- "If you get this\nmessage in error, "
- "hold down the Ctrl key while booting, "
- "and I\nwill take your word for it.\n",
- oreg.eax.w[0], mem);
- writestr(buf);
- kaboom();
- }
- }
-}
-
-extern uint32_t BIOS_timer_next;
-extern uint32_t timer_irq;
-static inline void bios_timer_init(void)
-{
- unsigned long next;
- uint32_t *hook = (uint32_t *)BIOS_timer_hook;
-
- next = *hook;
- BIOS_timer_next = next;
- *hook = (uint32_t)&timer_irq;
-}
-
-extern void printf_init(void);
-void init(com32sys_t *regs __unused)
+void init(void)
{
- int i;
-
- /* Initialize timer */
- bios_timer_init();
-
- for (i = 0; i < 256; i++)
- KbdMap[i] = i;
-
- adjust_screen();
- printf_init();
-
- /* Init the memory subsystem */
- mem_init();
-
- /* CPU-dependent initialization and related checks. */
- check_escapes();
+ firmware->init();
}
diff --git a/core/init.inc b/core/init.inc
index 5cb8e49a..995f9825 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -33,7 +33,9 @@ common_init:
cmp eax,__pm_code_len
jne kaboom
- extern init
+ extern syslinux_register_bios, init
+
+ pm_call syslinux_register_bios
pm_call init
;
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 5930a1ee..06291f8b 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -1167,7 +1167,7 @@ init_fs:
mov ebx,[Hidden+4]
mov si,[bsHeads]
mov di,[bsSecPerTrack]
- pm_call fs_init
+ pm_call pm_fs_init
pm_call load_env32
enter_command:
auto_boot:
diff --git a/core/lzo/enter.ash b/core/lzo/enter.ash
index 49c455d6..e865c4cb 100644
--- a/core/lzo/enter.ash
+++ b/core/lzo/enter.ash
@@ -42,12 +42,23 @@
//
************************************************************************/
+#if __SIZEOF_POINTER__ == 4
pushl %ebp
pushl %edi
pushl %esi
pushl %ebx
pushl %ecx
pushl %edx
+#elif __SIZEOF_POINTER__ == 8
+ push %rbp
+ push %rdi
+ push %rsi
+ push %rbx
+ push %rcx
+ push %rdx
+#else
+#error "unsupported architecture"
+#endif
subl $12,%esp
cld
diff --git a/core/lzo/leave.ash b/core/lzo/leave.ash
index 9550b46f..f77e2efd 100644
--- a/core/lzo/leave.ash
+++ b/core/lzo/leave.ash
@@ -62,12 +62,23 @@
negl %eax
addl $12,%esp
+#if __SIZEOF_POINTER__ == 4
popl %edx
popl %ecx
popl %ebx
popl %esi
popl %edi
popl %ebp
+#elif __SIZEOF_POINTER__ == 8
+ pop %rdx
+ pop %rcx
+ pop %rbx
+ pop %rsi
+ pop %rdi
+ pop %rbp
+#else
+#error "unsupported architecture"
+#endif
#if 1
ret
#else
diff --git a/core/lzo/lzo_asm.h b/core/lzo/lzo_asm.h
index 55fdf6d1..5e870b85 100644
--- a/core/lzo/lzo_asm.h
+++ b/core/lzo/lzo_asm.h
@@ -42,10 +42,12 @@
// <asmconfig.h>
************************************************************************/
+/*support both i386 and x86_64 */
+/*
#if !defined(__i386__)
# error
#endif
-
+*/
#if !defined(IN_CONFIGURE)
#if defined(LZO_HAVE_CONFIG_H)
# include <config.h>
diff --git a/core/mem/free.c b/core/mem/free.c
index 2908943b..d22813d4 100644
--- a/core/mem/free.c
+++ b/core/mem/free.c
@@ -75,6 +75,9 @@ void free(void *ptr)
if ( !ptr )
return;
+#ifdef SYSLINUX_EFI
+ FreePool(ptr);
+#else
ah = (struct free_arena_header *)
((struct arena_header *)ptr - 1);
@@ -83,6 +86,7 @@ void free(void *ptr)
#endif
__free_block(ah);
+#endif
/* Here we could insert code to return memory to the system. */
}
diff --git a/core/mem/init.c b/core/mem/init.c
index abfe23ae..0526dfbf 100644
--- a/core/mem/init.c
+++ b/core/mem/init.c
@@ -64,11 +64,11 @@ static void mpool_dump(enum heap heap)
}
#endif
+uint16_t *bios_free_mem;
void mem_init(void)
{
struct free_arena_header *fp;
int i;
- uint16_t *bios_free_mem = (uint16_t *)0x413;
//dprintf("enter");
diff --git a/core/mem/malloc.c b/core/mem/malloc.c
index fa1d26a7..865de1e7 100644
--- a/core/mem/malloc.c
+++ b/core/mem/malloc.c
@@ -69,6 +69,9 @@ static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
dprintf("_malloc(%zu, %u, %u) @ %p = ",
size, heap, tag, __builtin_return_address(0));
+#ifdef SYSLINUX_EFI
+ p = AllocatePool(size);
+#else
if (size) {
/* Add the obligatory arena header, and round up */
size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
@@ -81,6 +84,7 @@ static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
}
}
}
+#endif
dprintf("%p\n", p);
return p;
@@ -114,6 +118,12 @@ void *realloc(void *ptr, size_t size)
void *newptr;
size_t newsize, oldsize, xsize;
+#ifdef SYSLINUX_EFI
+ newptr = AllocatePool(size);
+ memcpy(newptr, ptr, size);
+ FreePool(ptr);
+ return newptr;
+#else
if (!ptr)
return malloc(size);
@@ -205,6 +215,7 @@ void *realloc(void *ptr, size_t size)
return newptr;
}
}
+#endif
}
void *zalloc(size_t size)
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index ef9c7238..aa11702d 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -175,7 +175,7 @@ _start1:
;
mov eax,ROOT_FS_OPS
xor ebp,ebp
- pm_call fs_init
+ pm_call pm_fs_init
section .rodata
alignz 4
@@ -401,7 +401,7 @@ pxenv:
jnz .store_stack
.disable_timer:
- call timer_cleanup
+ call bios_timer_cleanup
.store_stack:
mov [cs:PXEStack],sp
diff --git a/core/syslinux.ld b/core/syslinux.ld
index f024b92d..edd89e86 100644
--- a/core/syslinux.ld
+++ b/core/syslinux.ld
@@ -26,6 +26,7 @@ SECTIONS
{
/* Prefix structure for the compression program */
. = 0;
+ __module_start = .;
.prefix : {
*(.prefix)
}
diff --git a/core/timer.inc b/core/timer.inc
index 2bf0a219..9f42fdf2 100644
--- a/core/timer.inc
+++ b/core/timer.inc
@@ -32,8 +32,8 @@ timer_init:
mov dword [BIOS_timer_hook],timer_irq
ret
- global timer_cleanup
-timer_cleanup:
+ global bios_timer_cleanup
+bios_timer_cleanup:
; Unhook INT 1Ch
mov eax,[BIOS_timer_next]
mov [BIOS_timer_hook],eax
diff --git a/core/x86_64/syslinux.ld b/core/x86_64/syslinux.ld
new file mode 100644
index 00000000..10571120
--- /dev/null
+++ b/core/x86_64/syslinux.ld
@@ -0,0 +1,428 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+EXTERN(_start)
+ENTRY(_start)
+
+STACK32_LEN = 65536;
+
+SECTIONS
+{
+ /* Prefix structure for the compression program */
+ . = 0;
+ __module_start = .;
+ .prefix : {
+ *(.prefix)
+ }
+
+ /* "Early" sections (before the load) */
+ . = 0x1000;
+
+ .earlybss (NOLOAD) : {
+ __earlybss_start = .;
+ *(.earlybss)
+ __earlybss_end = .;
+ }
+ __earlybss_len = ABSOLUTE(__earlybss_end) - ABSOLUTE(__earlybss_start);
+ __earlybss_dwords = (__earlybss_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .bss16 (NOLOAD) : {
+ __bss16_start = .;
+ *(.bss16)
+ __bss16_end = .;
+ }
+ __bss16_len = ABSOLUTE(__bss16_end) - ABSOLUTE(__bss16_start);
+ __bss16_dwords = (__bss16_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .config : AT (__config_lma) {
+ __config_start = .;
+ *(.config)
+ __config_end = .;
+ }
+ __config_len = ABSOLUTE(__config_end) - ABSOLUTE(__config_start);
+ __config_dwords = (__config_len + 3) >> 2;
+
+ /* Generated and/or copied code */
+
+ . = ALIGN(128); /* Minimum separation from mutable data */
+ .replacestub : AT (__replacestub_lma) {
+ __replacestub_start = .;
+ *(.replacestub)
+ __replacestub_end = .;
+ }
+ __replacestub_len = ABSOLUTE(__replacestub_end) - ABSOLUTE(__replacestub_start);
+ __replacestub_dwords = (__replacestub_len + 3) >> 2;
+
+ . = ALIGN(16);
+ __gentextnr_lma = .;
+ .gentextnr : AT(__gentextnr_lma) {
+ __gentextnr_start = .;
+ *(.gentextnr)
+ __gentextnr_end = .;
+ }
+ __gentextnr_len = ABSOLUTE(__gentextnr_end) - ABSOLUTE(__gentextnr_start);
+ __gentextnr_dwords = (__gentextnr_len + 3) >> 2;
+
+ . = STACK_BASE;
+ .stack16 : AT(STACK_BASE) {
+ __stack16_start = .;
+ . += STACK_LEN;
+ __stack16_end = .;
+ }
+ __stack16_len = ABSOLUTE(__stack16_end) - ABSOLUTE(__stack16_start);
+ __stack16_dwords = (__stack16_len + 3) >> 2;
+
+ /* Initialized sections */
+
+ . = 0x7c00;
+ .init : {
+ FILL(0x90909090)
+ __init_start = .;
+ *(.init)
+ __init_end = .;
+ }
+ __init_len = ABSOLUTE(__init_end) - ABSOLUTE(__init_start);
+ __init_dwords = (__init_len + 3) >> 2;
+
+ .text16 : {
+ FILL(0x90909090)
+ __text16_start = .;
+ *(.text16)
+ __text16_end = .;
+ }
+ __text16_len = ABSOLUTE(__text16_end) - ABSOLUTE(__text16_start);
+ __text16_dwords = (__text16_len + 3) >> 2;
+
+ /*
+ * .textnr is used for 32-bit code that is used on the code
+ * path to initialize the .text segment
+ */
+ . = ALIGN(16);
+ .textnr : {
+ FILL(0x90909090)
+ __textnr_start = .;
+ *(.textnr)
+ __textnr_end = .;
+ }
+ __textnr_len = ABSOLUTE(__textnr_end) - ABSOLUTE(__textnr_start);
+ __textnr_dwords = (__textnr_len + 3) >> 2;
+
+ . = ALIGN(16);
+ __bcopyxx_start = .;
+
+ .bcopyxx.text : {
+ FILL(0x90909090)
+ __bcopyxx_text_start = .;
+ *(.bcopyxx.text)
+ __bcopyxx_text_end = .;
+ }
+ __bcopyxx_text_len = ABSOLUTE(__bcopyxx_text_end) - ABSOLUTE(__bcopyxx_text_start);
+ __bcopyxx_text_dwords = (__bcopyxx_text_len + 3) >> 2;
+
+ .bcopyxx.data : {
+ __bcopyxx_data_start = .;
+ *(.bcopyxx.text)
+ __bcopyxx_data_end = .;
+ }
+ __bcopyxx_data_len = ABSOLUTE(__bcopyxx_data_end) - ABSOLUTE(__bcopyxx_data_start);
+ __bcopyxx_data_dwords = (__bcopyxx_data_len + 3) >> 2;
+
+ __bcopyxx_end = .;
+ __bcopyxx_len = ABSOLUTE(__bcopyxx_end) - ABSOLUTE(__bcopyxx_start);
+ __bcopyxx_dwords = (__bcopyxx_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .data16 : {
+ __data16_start = .;
+ *(.data16)
+ __data16_end = .;
+ }
+ __data16_len = ABSOLUTE(__data16_end) - ABSOLUTE(__data16_start);
+ __data16_dwords = (__data16_len + 3) >> 2;
+
+ . = ALIGN(4);
+ __config_lma = .;
+ . += SIZEOF(.config);
+
+ . = ALIGN(4);
+ __replacestub_lma = .;
+ . += SIZEOF(.replacestub);
+
+ /* The 32-bit code loads above the non-progbits sections */
+
+ . = ALIGN(16);
+ __pm_code_lma = .;
+
+ __high_clear_start = .;
+
+ . = ALIGN(512);
+ .adv (NOLOAD) : {
+ __adv_start = .;
+ *(.adv)
+ __adv_end = .;
+ }
+ __adv_len = ABSOLUTE(__adv_end) - ABSOLUTE(__adv_start);
+ __adv_dwords = (__adv_len + 3) >> 2;
+
+ /* Late uninitialized sections */
+
+ . = ALIGN(4);
+ .uibss (NOLOAD) : {
+ __uibss_start = .;
+ *(.uibss)
+ __uibss_end = .;
+ }
+ __uibss_len = ABSOLUTE(__uibss_end) - ABSOLUTE(__uibss_start);
+ __uibss_dwords = (__uibss_len + 3) >> 2;
+
+ _end16 = .;
+ __assert_end16 = ASSERT(_end16 <= 0x10000, "64K overflow");
+
+ /*
+ * Special 16-bit segments
+ */
+
+ . = ALIGN(65536);
+ .real_mode (NOLOAD) : {
+ *(.real_mode)
+ }
+ real_mode_seg = core_real_mode >> 4;
+
+ . = ALIGN(65536);
+ .xfer_buf (NOLOAD) : {
+ *(.xfer_buf)
+ }
+ xfer_buf_seg = core_xfer_buf >> 4;
+
+ /*
+ * The auxilliary data segment is used by the 16-bit code
+ * for items that don't need to live in the bottom 64K.
+ */
+
+ . = ALIGN(16);
+ .auxseg (NOLOAD) : {
+ __auxseg_start = .;
+ *(.auxseg)
+ __auxseg_end = .;
+ }
+ __auxseg_len = ABSOLUTE(__auxseg_end) - ABSOLUTE(__auxseg_start);
+ __auxseg_dwords = (__auxseg_len + 3) >> 2;
+ aux_seg = __auxseg_start >> 4;
+
+ /*
+ * Used to allocate lowmem buffers from 32-bit code
+ */
+ .lowmem (NOLOAD) : {
+ __lowmem_start = .;
+ *(.lowmem)
+ __lowmem_end = .;
+ }
+ __lowmem_len = ABSOLUTE(__lowmem_end) - ABSOLUTE(__lowmem_start);
+ __lowmem_dwords = (__lowmem_len + 3) >> 2;
+
+ __high_clear_end = .;
+
+ __high_clear_len = ABSOLUTE(__high_clear_end) - ABSOLUTE(__high_clear_start);
+ __high_clear_dwords = (__high_clear_len + 3) >> 2;
+
+ /* Start of the lowmem heap */
+ . = ALIGN(16);
+ __lowmem_heap = .;
+
+ /*
+ * 32-bit code. This is a hack for the moment due to the
+ * real-mode segments also allocated.
+ */
+
+ . = 0x100000;
+
+ __pm_code_start = .;
+
+ __text_vma = .;
+ __text_lma = __pm_code_lma;
+ .text : AT(__text_lma) {
+ FILL(0x90909090)
+ __text_start = .;
+ *(.text)
+ *(.text.*)
+ __text_end = .;
+ }
+
+ . = ALIGN(16);
+
+ __rodata_vma = .;
+ __rodata_lma = __rodata_vma + __text_lma - __text_vma;
+ .rodata : AT(__rodata_lma) {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ __rodata_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __ctors_vma = .;
+ __ctors_lma = __ctors_vma + __text_lma - __text_vma;
+ .ctors : AT(__ctors_lma) {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctors_end = .;
+ }
+
+ __dtors_vma = .;
+ __dtors_lma = __dtors_vma + __text_lma - __text_vma;
+ .dtors : AT(__dtors_lma) {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __dtors_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __dynsym_vma = .;
+ __dynsym_lma = __dynsym_vma + __text_lma - __text_vma;
+ .dynsym : AT(__dynsym_lma) {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+ __dynsym_len = __dynsym_end - __dynsym_start;
+
+ . = ALIGN(4);
+
+ __dynstr_vma = .;
+ __dynstr_lma = __dynstr_vma + __text_lma - __text_vma;
+ .dynstr : AT(__dynstr_lma) {
+ __dynstr_start = .;
+ *(.dynstr)
+ __dynstr_end = .;
+ }
+ __dynstr_len = __dynstr_end - __dynstr_start;
+
+ . = ALIGN(4);
+
+ __gnu_hash_vma = .;
+ __gnu_hash_lma = __gnu_hash_vma + __text_lma - __text_vma;
+ .gnu.hash : AT(__gnu_hash_lma) {
+ __gnu_hash_start = .;
+ *(.gnu.hash)
+ __gnu_hash_end = .;
+ }
+
+
+ . = ALIGN(4);
+
+ __dynlink_vma = .;
+ __dynlink_lma = __dynlink_vma + __text_lma - __text_vma;
+ .dynlink : AT(__dynlink_lma) {
+ __dynlink_start = .;
+ *(.dynlink)
+ __dynlink_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __got_vma = .;
+ __got_lma = __got_vma + __text_lma - __text_vma;
+ .got : AT(__got_lma) {
+ __got_start = .;
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __dynamic_vma = .;
+ __dynamic_lma = __dynamic_vma + __text_lma - __text_vma;
+ .dynamic : AT(__dynamic_lma) {
+ __dynamic_start = .;
+ *(.dynamic)
+ __dynamic_end = .;
+ }
+
+ . = ALIGN(16);
+
+ __data_vma = .;
+ __data_lma = __data_vma + __text_lma - __text_vma;
+ .data : AT(__data_lma) {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ __data_end = .;
+ }
+
+ __pm_code_end = .;
+ __pm_code_len = ABSOLUTE(__pm_code_end) - ABSOLUTE(__pm_code_start);
+ __pm_code_dwords = (__pm_code_len + 3) >> 2;
+
+ . = ALIGN(128);
+
+ __bss_vma = .;
+ __bss_lma = .; /* Dummy */
+ .bss (NOLOAD) : AT (__bss_lma) {
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ __bss_end = .;
+ }
+ __bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+ __bss_dwords = (__bss_len + 3) >> 2;
+
+ /* Very large objects which don't need to be zeroed */
+
+ __hugebss_vma = .;
+ __hugebss_lma = .; /* Dummy */
+ .hugebss (NOLOAD) : AT (__hugebss_lma) {
+ __hugebss_start = .;
+ *(.hugebss)
+ *(.hugebss.*)
+ __hugebss_end = .;
+ }
+ __hugebss_len = ABSOLUTE(__hugebss_end) - ABSOLUTE(__hugebss_start);
+ __hugebss_dwords = (__hugebss_len + 3) >> 2;
+
+
+ /* XXX: This stack should be unified with the COM32 stack */
+ __stack_vma = .;
+ __stack_lma = .; /* Dummy */
+ .stack (NOLOAD) : AT(__stack_lma) {
+ __stack_start = .;
+ *(.stack)
+ __stack_end = .;
+ }
+ __stack_len = ABSOLUTE(__stack_end) - ABSOLUTE(__stack_start);
+ __stack_dwords = (__stack_len + 3) >> 2;
+
+ _end = .;
+
+ /* COM32R and kernels are loaded after our own PM code */
+ . = ALIGN(65536);
+ free_high_memory = .;
+
+ /* Stuff we don't need... */
+ /DISCARD/ : {
+ *(.eh_frame)
+ }
+}
diff --git a/diag/mbr/Makefile b/diag/mbr/Makefile
index 79ff9f01..f8582053 100644
--- a/diag/mbr/Makefile
+++ b/diag/mbr/Makefile
@@ -27,7 +27,7 @@ all: handoff.bin
.PRECIOUS: %.elf
%.elf: %.o $(mbrdir)/mbr.ld
- $(LD) $(LDFLAGS) -T $(mbrdir)/mbr.ld -e _start -o $@ $<
+ $(LD) $(LDFLAGS) -T $(mbrdir)/$(ARCH)/mbr.ld -e _start -o $@ $<
%.bin: %.elf $(mbrdir)/checksize.pl
$(OBJCOPY) -O binary $< $@
diff --git a/dos/stdlib.h b/dos/stdlib.h
index d3467056..d9826706 100644
--- a/dos/stdlib.h
+++ b/dos/stdlib.h
@@ -2,7 +2,14 @@
#define STDLIB_H
typedef int ssize_t;
+/* size_t is defined elsewhere */
+#if __SIZEOF_POINTER__ == 4
typedef unsigned int size_t;
+#elif __SIZEOF_POINTER__ == 8
+typedef unsigned long size_t;
+#else
+#error "unsupported architecture"
+#endif
void __attribute__ ((noreturn)) exit(int);
diff --git a/efi/Makefile b/efi/Makefile
new file mode 100644
index 00000000..3304d763
--- /dev/null
+++ b/efi/Makefile
@@ -0,0 +1,67 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2011 Intel Corporation; author: Matt Fleming
+##
+## 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, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+topdir = ..
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/lib.mk
+include $(MAKEDIR)/efi.mk
+
+CORE_CSRC := $(wildcard $(core)/*.c $(core)/*/*.c $(core)/*/*/*.c)
+CORE_COBJ := $(patsubst %.c,%.o,$(CORE_CSRC))
+
+# Don't include console objects
+CORE_OBJS = $(filter-out $(core)/hello.o $(core)/rawcon.o \
+ $(core)/plaincon.o $(core)/strcasecmp.o $(core)/bios.o \
+ $(core)/fs/diskio_bios.o,$(CORE_COBJ))
+LIB_OBJS = $(addprefix $(com32)/lib/,$(CORELIBOBJS))
+
+CSRC = $(wildcard *.c)
+OBJ = $(patsubst %.c,%.o,$(CSRC))
+OBJS = $(filter-out wrapper.o,$(OBJ))
+
+OBJS += $(core)/codepage.o
+
+# The targets to build in this directory
+BTARGET = syslinux.efi
+
+syslinux.so: $(OBJS) $(CORE_OBJS) $(LIB_OBJS)
+ $(LD) $(LDFLAGS) -o $@ $^ -lgnuefi -lefi
+
+# We need to rename the .hash section because the EFI firmware
+# linker really doesn't like it.
+# $(OBJCOPY) --rename-section .gnu.hash=.sdata,load,data,alloc $^ $@
+#syslinux.so: syslinux1.so
+# cp $^ $@
+
+wrapper: wrapper.c
+ $(CC) $^ -o $@
+
+#
+# Build the wrapper app and wrap our .so to produce a .efi
+syslinux.efi: syslinux.so wrapper
+ ./wrapper syslinux.so $@
+
+all: $(BTARGET)
+
+$(core)/codepage.o: ../codepage/cp865.cp
+ cp ../codepage/cp865.cp codepage.cp
+ $(CC) $(SFLAGS) -c -o $@ $(core)/codepage.S
+
+tidy dist:
+ rm -f *.so *.o
+ find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
+ xargs -0r rm -f
+
+clean: tidy
+
+spotless: clean
+ rm -f $(BTARGET) wrapper
diff --git a/efi/adv.c b/efi/adv.c
new file mode 100644
index 00000000..3dec3cc8
--- /dev/null
+++ b/efi/adv.c
@@ -0,0 +1,362 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2012 Intel Corporation; author: H. Peter Anvin
+ * Chandramouli Narayanan
+ *
+ * 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, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * adv.c
+ *
+ * Core ADV I/O
+ * Code consolidated from libinstaller/adv*.c and core/adv.inc with the
+ * addition of EFI support
+ *
+ * Return 0 on success, -1 on error, and set errno.
+ *
+ */
+#define _GNU_SOURCE
+
+#include "adv.h"
+
+#define IS_SYSLINUX /* remove this: test build only */
+
+unsigned char syslinux_adv[2 * ADV_SIZE];
+
+static void cleanup_adv(unsigned char *advbuf)
+{
+ int i;
+ uint32_t csum;
+
+ /* Make sure both copies agree, and update the checksum */
+ *(uint32_t *)advbuf = ADV_MAGIC1;
+
+ csum = ADV_MAGIC2;
+ for (i = 8; i < ADV_SIZE - 4; i += 4)
+ csum -= *(uint32_t *)(advbuf + i);
+
+ *(uint32_t *)(advbuf + 4) = csum;
+ *(uint32_t *)(advbuf + ADV_SIZE - 4) = ADV_MAGIC3;
+
+ memcpy(advbuf + ADV_SIZE, advbuf, ADV_SIZE);
+}
+
+void syslinux_reset_adv(unsigned char *advbuf)
+{
+ /* Create an all-zero ADV */
+ memset(advbuf + 2 * 4, 0, ADV_LEN);
+ cleanup_adv(advbuf);
+}
+
+static int adv_consistent(const unsigned char *p)
+{
+ int i;
+ uint32_t csum;
+
+ if (*(uint32_t *)p != ADV_MAGIC1 ||
+ *(uint32_t *)(p + ADV_SIZE - 4) != ADV_MAGIC3)
+ return 0;
+
+ csum = 0;
+ for (i = 4; i < ADV_SIZE - 4; i += 4)
+ csum += *(uint32_t *)(p + i);
+
+ return csum == ADV_MAGIC2;
+}
+
+/*
+ * Verify that an in-memory ADV is consistent, making the copies consistent.
+ * If neither copy is OK, return -1 and call syslinux_reset_adv().
+ */
+int syslinux_validate_adv(unsigned char *advbuf)
+{
+ if (adv_consistent(advbuf + 0 * ADV_SIZE)) {
+ memcpy(advbuf + ADV_SIZE, advbuf, ADV_SIZE);
+ return 0;
+ } else if (adv_consistent(advbuf + 1 * ADV_SIZE)) {
+ memcpy(advbuf, advbuf + ADV_SIZE, ADV_SIZE);
+ return 0;
+ } else {
+ syslinux_reset_adv(advbuf);
+ return -1;
+ }
+}
+
+/*
+ * Read the ADV from an existing instance, or initialize if invalid.
+ * Returns -1 on fatal errors, 0 if ADV is okay, 1 if the ADV is
+ * invalid, and 2 if the file does not exist.
+ */
+
+/* make_filespec
+ * Take the ASCII pathname and filename and concatenate them
+ * into an allocated memory space as unicode file specification string.
+ * The path and cfg ASCII strings are assumed to be null-terminated.
+ * For EFI, the separation character in the path name is '\'
+ * and therefore it is assumed that the file spec uses '\' as separation char
+ *
+ * The function returns
+ * 0 if successful and fspec is a valid allocated CHAR16 pointer
+ * Caller is responsible to free up the allocated filespec string
+ * -1 otherwise
+ *
+ */
+static int make_filespec(CHAR16 **fspec, const char *path, const char *cfg)
+{
+ CHAR16 *p;
+ int size, append;
+
+ /* allocate size for a CHAR16 string */
+ size = sizeof(CHAR16) * (strlena((CHAR8 *)path)+strlena((CHAR8 *)cfg)+2); /* including null */
+ *fspec = malloc(size);
+ if (!*fspec) return -1;
+
+ append = path[strlena((CHAR8 *)path) - 1] != '\\';
+ for (p = *fspec; *path; path++, p++)
+ *p = (CHAR16)*path;
+ /* append the separation character to the path if need be */
+ if (append) *p++ = (CHAR16)'\\';
+ for (; *cfg; cfg++, p++)
+ *p = (CHAR16)*cfg;
+ *p = (CHAR16)CHAR_NULL;
+
+ return 0;
+}
+
+
+/* TODO:
+ * set_attributes() and clear_attributes() are supported for VFAT only
+ */
+int read_adv(const char *path, const char *cfg)
+{
+ CHAR16 *file;
+ EFI_FILE_HANDLE fd;
+ EFI_FILE_INFO st;
+ int err = 0;
+ int rv;
+
+ rv = make_filespec(&file, path, cfg);
+ if (rv < 0 || !file) {
+ efi_perror(L"read_adv");
+ return -1;
+ }
+
+ /* TBD: Not sure if EFI accepts the attribute read only
+ * even if an existing file is opened for read access
+ */
+ fd = efi_open(file, EFI_FILE_MODE_READ);
+ if (!fd) {
+ if (efi_errno != EFI_NOT_FOUND) {
+ err = -1;
+ } else {
+ syslinux_reset_adv(syslinux_adv);
+ err = 2; /* Nonexistence is not a fatal error */
+ }
+ } else if (!efi_fstat(fd, &st)) {
+ err = -1;
+ } else if (st.FileSize < 2 * ADV_SIZE) {
+ /* Too small to be useful */
+ syslinux_reset_adv(syslinux_adv);
+ err = 0; /* Nothing to read... */
+ } else if (efi_xpread(fd, syslinux_adv, 2 * ADV_SIZE,
+ st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ } else {
+ /* We got it... maybe? */
+ err = syslinux_validate_adv(syslinux_adv) ? 1 : 0;
+ }
+
+ if (err < 0)
+ efi_perror(file);
+ if (fd)
+ efi_close(fd);
+ free(file);
+
+ return err;
+}
+
+/* For EFI platform, initialize ADV by opening ldlinux.sys or extlinux.sys
+ * as configured and return the primary (adv0) and alternate (adv1)
+ * data into caller's buffer. File remains open for subsequent
+ * operations. This routine is to be called from comboot
+ * vector. Currently only IS_SYSLINUX or IS_EXTLINUX is supported
+ *
+ * TODO:
+ * 1. Need to set the path to ldlinux.sys or extlinux.sys; currently null
+ * 2. What if there are errors?
+ */
+void efi_adv_init(void)
+{
+ char *name;
+ int rv;
+ int err = 0;
+ unsigned char *advbuf = syslinux_adv;
+ EFI_FILE_HANDLE fd; /* handle to ldlinux.sys or extlinux.sys */
+ CHAR16 *file;
+ EFI_FILE_INFO st, xst;
+
+#if defined IS_SYSLINUX
+ name = SYSLINUX_FILE;
+#elif defined IS_EXTLINUX
+ name = EXTLINUX_FILE;
+#else
+ #error "IS_SYSLINUX or IS_EXTLINUX must be specified to build ADV"
+#endif
+ /* FIXME: No path defined to syslinux/extlinux file */
+ rv = make_filespec(&file, "", name);
+ if (rv < 0 || !file) {
+ efi_errno = EFI_OUT_OF_RESOURCES;
+ efi_perror(L"efi_adv_init:");
+ return;
+ }
+
+ fd = efi_open(file, EFI_FILE_MODE_READ);
+ if (fd == (EFI_FILE_HANDLE)NULL) {
+ err = -1;
+ efi_printerr(L"efi_adv_init: Unable to open file %s\n", file);
+ } else if (efi_fstat(fd, &st)) {
+ err = -1;
+ efi_printerr(L"efi_adv_init: Unable to get info for file %s\n", file);
+ } else if (st.FileSize < 2 * ADV_SIZE) {
+ /* Too small to be useful */
+ err = -2;
+ efi_printerr(L"efi_adv_init: File %s size too small to be useful %s\n", file);
+ } else if (efi_xpread(fd, advbuf, 2 * ADV_SIZE,
+ st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ efi_printerr(L"efi_adv_init: Error reading ADV data from file %s\n", file);
+ } else {
+ /* We got it... maybe? */
+ __syslinux_adv_ptr = &syslinux_adv[8]; /* skip head, csum */
+ __syslinux_adv_size = ADV_LEN;
+
+ err = syslinux_validate_adv(advbuf) ? -2 : 0;
+ if (!err) {
+ /* Got a good one*/
+ efi_clear_attributes(fd);
+
+ /* Need to re-open read-write */
+ efi_close(fd);
+ /* There is no SYNC attribute with EFI open */
+ fd = efi_open(file, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
+ /* on error, only explicit comparison with null handle works */
+ if (fd == (EFI_FILE_HANDLE)NULL) {
+ err = -1;
+ efi_perror(L"efi_adv_init:");
+ } else if (efi_fstat(fd, &xst) || xst.FileSize != st.FileSize) {
+ /* device/inode info don't exist in the EFI file info structure */
+ efi_perror(L"efi_adv_init: file status error/mismatch");
+ err = -2;
+ }
+ /* TODO: Do we need to set attributes of the sys file? */
+ }
+ }
+ if (file)
+ free(file);
+ if (fd != 0)
+ efi_close(fd);
+ /* TODO: In case of errors, we could set efi_errno to EFI_LOAD_ERROR
+ * to mean that ADV could not be loaded up
+ */
+}
+
+/* For EFI platform, write 2 * ADV_SIZE data to the file opened
+ * at ADV initialization. (i.e ldlinux.sys or extlinux.sys).
+ *
+ * TODO:
+ * 1. Validate assumption: write back to file from __syslinux_adv_ptr
+ * 2. What if there errors?
+ * 3. Do we need to set the attributes of the sys file?
+ *
+ */
+int efi_adv_write(void)
+{
+ char *name;
+ unsigned char advtmp[2 * ADV_SIZE];
+ unsigned char *advbuf = syslinux_adv;
+ int rv;
+ int err = 0;
+ EFI_FILE_HANDLE fd; /* handle to ldlinux.sys or extlinux.sys */
+ CHAR16 *file;
+ EFI_FILE_INFO st, xst;
+
+#if defined IS_SYSLINUX
+ name = SYSLINUX_FILE;
+#elif defined IS_EXTLINUX
+ name = EXTLINUX_FILE;
+#else
+ #error "IS_SYSLINUX or IS_EXTLINUX must be specified to build ADV"
+#endif
+ rv = make_filespec(&file, "", name);
+ if (rv < 0 || !file) {
+ efi_errno = EFI_OUT_OF_RESOURCES;
+ efi_perror(L"efi_adv_write:");
+ return -1;
+ }
+
+ fd = efi_open(file, EFI_FILE_MODE_READ);
+ if (fd == (EFI_FILE_HANDLE)NULL) {
+ err = -1;
+ efi_printerr(L"efi_adv_write: Unable to open file %s\n", file);
+ } else if (efi_fstat(fd, &st)) {
+ err = -1;
+ efi_printerr(L"efi_adv_write: Unable to get info for file %s\n", file);
+ } else if (st.FileSize < 2 * ADV_SIZE) {
+ /* Too small to be useful */
+ err = -2;
+ efi_printerr(L"efi_adv_write: File size too small to be useful for file %s\n", file);
+ } else if (efi_xpread(fd, advtmp, 2 * ADV_SIZE,
+ st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ efi_printerr(L"efi_adv_write: Error reading ADV data from file %s\n", file);
+ } else {
+ cleanup_adv(advbuf);
+ err = syslinux_validate_adv(advbuf) ? -2 : 0;
+
+ if (!err) {
+ /* Got a good one, write our own ADV here */
+ efi_clear_attributes(fd);
+
+ /* Need to re-open read-write */
+ efi_close(fd);
+ /* There is no SYNC attribute with EFI open */
+ fd = efi_open(file, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
+ if (fd == (EFI_FILE_HANDLE)NULL) {
+ err = -1;
+ } else if (efi_fstat(fd, &xst) || xst.FileSize != st.FileSize) {
+ efi_perror(L"efi_adv_write: file status error/mismatch");
+ err = -2;
+ }
+ /* Write our own version ... */
+ if (efi_xpwrite(fd, advbuf, 2 * ADV_SIZE,
+ st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+ err = -1;
+ efi_printerr(L"efi_adv_write: Error write ADV data to file %s\n", file);
+ }
+ if (!err) {
+ efi_sync(fd);
+ efi_set_attributes(fd);
+ }
+ }
+ }
+
+ if (err == -2)
+ efi_printerr(L"%s: cannot write auxilliary data (need --update)?\n",
+ file);
+ else if (err == -1)
+ efi_perror(L"efi_adv_write:");
+
+ if (fd)
+ efi_close(fd);
+ if (file)
+ free(file);
+
+ return err;
+}
diff --git a/efi/adv.h b/efi/adv.h
new file mode 100644
index 00000000..e8ccb352
--- /dev/null
+++ b/efi/adv.h
@@ -0,0 +1,29 @@
+#ifndef _H_EFI_ADV_
+#define _H_EFI_ADV_
+
+#include "efi.h"
+#include "fio.h"
+#include <syslinux/firmware.h>
+
+/* ADV information */
+#define ADV_SIZE 512 /* Total size */
+#define ADV_LEN (ADV_SIZE-3*4) /* Usable data size */
+/* Currently, one of IS_SYSLINUX or IS_EXTLINUX must be defined for ADV */
+#define SYSLINUX_FILE "ldlinux.sys"
+#define EXTLINUX_FILE "extlinux.sys"
+
+#define ADV_MAGIC1 0x5a2d2fa5 /* Head signature */
+#define ADV_MAGIC2 0xa3041767 /* Total checksum */
+#define ADV_MAGIC3 0xdd28bf64 /* Tail signature */
+
+extern unsigned char syslinux_adv[2 * ADV_SIZE];
+extern void *__syslinux_adv_ptr;
+extern ssize_t __syslinux_adv_size;
+
+/* TODO: Revisit to ensure if these functions need to be exported */
+void syslinux_reset_adv(unsigned char *advbuf);
+int syslinux_validate_adv(unsigned char *advbuf);
+int read_adv(const char *path, const char *cfg);
+int write_adv(const char *path, const char *cfg);
+
+#endif
diff --git a/efi/console.c b/efi/console.c
new file mode 100644
index 00000000..1e475b17
--- /dev/null
+++ b/efi/console.c
@@ -0,0 +1,175 @@
+#include <syslinux/linux.h>
+#include "efi.h"
+
+extern EFI_GUID GraphicsOutputProtocol;
+
+void writechr(char data)
+{
+ Print(L"Wanted to print something\n");
+}
+
+static inline EFI_STATUS open_protocol(EFI_HANDLE handle, EFI_GUID *protocol,
+ void **interface, EFI_HANDLE agent,
+ EFI_HANDLE controller, UINT32 attributes)
+{
+ return uefi_call_wrapper(BS->OpenProtocol, 6, handle, protocol,
+ interface, agent, controller, attributes);
+}
+
+static inline EFI_STATUS
+gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN *size,
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **info)
+{
+ return uefi_call_wrapper(gop->QueryMode, 4, gop,
+ gop->Mode->Mode, size, info);
+}
+
+static inline void bit_mask(uint32_t mask, uint8_t *pos, uint8_t *size)
+{
+ *pos = 0;
+ *size = 0;
+
+ if (mask) {
+ while (!(mask & 0x1)) {
+ mask >>= 1;
+ (*pos)++;
+ }
+
+ while (mask & 0x1) {
+ mask >>= 1;
+ (*size)++;
+ }
+ }
+}
+
+void setup_screen(struct screen_info *si)
+{
+ EFI_HANDLE *handles = NULL;
+ EFI_STATUS status;
+ UINTN nr_handles;
+ UINTN size;
+ uint16_t lfb_width, lfb_height;
+ uint32_t lfb_base, lfb_size;
+ int i;
+
+ status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
+ NULL, &nr_handles, &handles);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, *found;
+ EFI_GRAPHICS_PIXEL_FORMAT pixel_fmt;
+ EFI_PIXEL_BITMASK pixel_info;
+ uint32_t pixel_scanline;
+
+ handles = AllocatePool(nr_handles);
+ if (!handles)
+ return;
+
+ status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
+ NULL, &nr_handles, &handles);
+ if (status != EFI_SUCCESS)
+ goto out;
+
+ found = NULL;
+ for (i = 0; i < (nr_handles / sizeof(EFI_HANDLE)); i++) {
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
+ EFI_PCI_IO *pciio = NULL;
+ EFI_HANDLE *h = handles[i];
+
+ status = open_protocol(h, &GraphicsOutputProtocol,
+ (void **)&gop,
+ image_handle, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ status = open_protocol(h, &PciIoProtocol,
+ (void **)&pciio,
+ image_handle, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ status = gop_query_mode(gop, &size, &info);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ if (!pciio && found)
+ continue;
+ found = gop;
+
+ lfb_width = info->HorizontalResolution;
+ lfb_height = info->VerticalResolution;
+ lfb_base = gop->Mode->FrameBufferBase;
+ lfb_size = gop->Mode->FrameBufferSize;
+ pixel_fmt = info->PixelFormat;
+ pixel_info = info->PixelInformation;
+ pixel_scanline = info->PixelsPerScanLine;
+
+ if (pciio)
+ break;
+ }
+
+ if (!found)
+ goto out;
+
+ si->orig_video_isVGA = 0x70; /* EFI framebuffer */
+
+ si->lfb_base = lfb_base;
+ si->lfb_size = lfb_size;
+ si->lfb_width = lfb_width;
+ si->lfb_height = lfb_height;
+ si->pages = 1;
+
+ switch (pixel_fmt) {
+ case PixelRedGreenBlueReserved8BitPerColor:
+ si->lfb_depth = 32;
+ si->lfb_linelength = pixel_scanline * 4;
+ si->red_size = 8;
+ si->red_pos = 0;
+ si->green_size = 8;
+ si->green_pos = 8;
+ si->blue_size = 8;
+ si->blue_pos = 16;
+ si->rsvd_size = 8;
+ si->rsvd_pos = 24;
+ break;
+ case PixelBlueGreenRedReserved8BitPerColor:
+ si->lfb_depth = 32;
+ si->lfb_linelength = pixel_scanline * 4;
+ si->red_size = 8;
+ si->red_pos = 16;
+ si->green_size = 8;
+ si->green_pos = 8;
+ si->blue_size = 8;
+ si->blue_pos = 0;
+ si->rsvd_size = 8;
+ si->rsvd_pos = 24;
+ break;
+ case PixelBitMask:
+ bit_mask(pixel_info.RedMask, &si->red_pos,
+ &si->red_size);
+ bit_mask(pixel_info.GreenMask, &si->green_pos,
+ &si->green_size);
+ bit_mask(pixel_info.BlueMask, &si->blue_pos,
+ &si->blue_size);
+ bit_mask(pixel_info.ReservedMask, &si->rsvd_pos,
+ &si->rsvd_size);
+ si->lfb_depth = si->red_size + si->green_size +
+ si->blue_size + si->rsvd_size;
+ si->lfb_linelength = (pixel_scanline * si->lfb_depth) / 8;
+ break;
+ default:
+ si->lfb_depth = 4;;
+ si->lfb_linelength = si->lfb_width / 2;
+ si->red_size = 0;
+ si->red_pos = 0;
+ si->green_size = 0;
+ si->green_pos = 0;
+ si->blue_size = 0;
+ si->blue_pos = 0;
+ si->rsvd_size = 0;
+ si->rsvd_pos = 0;
+ break;
+ }
+ }
+
+out:
+ FreePool(handles);
+}
diff --git a/efi/diskio.c b/efi/diskio.c
new file mode 100644
index 00000000..a4d558a4
--- /dev/null
+++ b/efi/diskio.c
@@ -0,0 +1,91 @@
+#include <fs.h>
+#include <ilog2.h>
+#include <disk.h>
+#include <dprintf.h>
+#include "efi.h"
+
+static inline EFI_STATUS read_blocks(EFI_BLOCK_IO *bio, uint32_t id,
+ sector_t lba, UINTN bytes, void *buf)
+{
+ return uefi_call_wrapper(bio->ReadBlocks, 5, bio, id, lba, bytes, buf);
+}
+
+static inline EFI_STATUS write_blocks(EFI_BLOCK_IO *bio, uint32_t id,
+ sector_t lba, UINTN bytes, void *buf)
+{
+ return uefi_call_wrapper(bio->WriteBlocks, 5, bio, id, lba, bytes, buf);
+}
+
+static int efi_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ struct disk_private *priv = disk->private;
+ EFI_BLOCK_IO *bio = priv->bio;
+ EFI_DISK_IO *dio = priv->dio;
+ EFI_STATUS status;
+ UINTN bytes = count * disk->sector_size;
+
+
+ if (is_write)
+ status = write_blocks(bio, disk->disk_number, lba, bytes, buf);
+ else
+ status = read_blocks(bio, disk->disk_number, lba, bytes, buf);
+
+ if (status != EFI_SUCCESS)
+ Print(L"Failed to %s blocks: 0x%x\n",
+ is_write ? L"write" : L"read",
+ status);
+
+ return count << disk->sector_shift;
+}
+
+struct disk *efi_disk_init(struct disk_private *priv)
+{
+ static struct disk disk;
+ EFI_HANDLE handle = priv->dev_handle;
+ unsigned int hard_max_transfer;
+ EFI_BLOCK_IO *bio;
+ EFI_DISK_IO *dio;
+ EFI_STATUS status;
+ int sector_size;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+ &DiskIoProtocol, (void **)&dio);
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+ &BlockIoProtocol, (void **)&bio);
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ /*
+ * XXX Do we need to map this to a BIOS disk number?
+ */
+ disk.disk_number = bio->Media->MediaId;
+
+ disk.sector_size = bio->Media->BlockSize;
+ disk.rdwr_sectors = efi_rdwr_sectors;
+ disk.sector_shift = ilog2(disk.sector_size);
+
+ dprintf("sector_size=%d, disk_number=%d\n", disk.sector_size,
+ disk.disk_number);
+
+ priv->bio = bio;
+ priv->dio = dio;
+ disk.private = priv;
+#if 0
+
+ disk.part_start = part_start;
+ disk.secpercyl = disk.h * disk.s;
+
+
+ disk.maxtransfer = MaxTransfer;
+
+ dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+ media_id, cdrom, ebios, sector_size, disk.sector_shift,
+ part_start, disk.maxtransfer);
+#endif
+
+ return &disk;
+}
diff --git a/efi/efi.h b/efi/efi.h
new file mode 100644
index 00000000..ed3fe8a3
--- /dev/null
+++ b/efi/efi.h
@@ -0,0 +1,13 @@
+#ifndef _SYSLINUX_EFI_H
+#define _SYSLINUX_EFI_H
+
+#include <core.h>
+#include <sys/types.h> /* needed for off_t */
+//#include <syslinux/version.h> /* avoid redefinition of __STDC_VERSION__ */
+#include <efi.h>
+#include <efilib.h>
+#include <efistdarg.h>
+
+extern EFI_HANDLE image_handle;
+
+#endif /* _SYSLINUX_EFI_H */
diff --git a/efi/fio.c b/efi/fio.c
new file mode 100644
index 00000000..f56cd5b4
--- /dev/null
+++ b/efi/fio.c
@@ -0,0 +1,283 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2012 Intel Corporation; author: H. Peter Anvin
+ * Chandramouli Narayanan
+ *
+ * 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, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Miscellaneous functions for UEFI support
+ * We assume that EFI library initialization has completed
+ * and we have access to the global EFI exported variables
+ *
+ */
+#include "efi.h"
+#include "fio.h"
+
+/* Variables that need to be exported
+ * efi_errno - maintains the errors from EFI calls to display error messages.
+ */
+EFI_STATUS efi_errno = EFI_SUCCESS;
+
+/* Locals
+ * vol_root - handle to the root device for file operations
+ */
+static EFI_FILE_HANDLE vol_root;
+
+/* Table of UEFI error messages to be indexed with the EFI errno
+ * Update error message list as needed
+ */
+static CHAR16 *uefi_errmsg[] = {
+ L"EFI_UNDEFINED", /* should not get here */
+ L"EFI_LOAD_ERROR",
+ L"EFI_INVALID_PARAMETER",
+ L"EFI_UNSUPPORTED",
+ L"EFI_BAD_BUFFER_SIZE",
+ L"EFI_BUFFER_TOO_SMALL",
+ L"EFI_NOT_READY",
+ L"EFI_DEVICE_ERROR",
+ L"EFI_WRITE_PROTECTED",
+ L"EFI_OUT_OF_RESOURCES",
+ L"EFI_VOLUME_CORRUPTED",
+ L"EFI_VOLUME_FULL",
+ L"EFI_NO_MEDIA",
+ L"EFI_MEDIA_CHANGED",
+ L"EFI_NOT_FOUND",
+ L"EFI_ACCESS_DENIED",
+ L"EFI_NO_RESPONSE",
+ L"EFI_NO_MAPPING",
+ L"EFI_TIMEOUT",
+ L"EFI_NOT_STARTED",
+ L"EFI_ALREADY_STARTED",
+ L"EFI_ABORTED",
+ L"EFI_ICMP_ERROR",
+ L"EFI_TFTP_ERROR",
+ L"EFI_PROTOCOL_ERROR"
+};
+
+static UINTN nerrs = sizeof(uefi_errmsg)/sizeof(CHAR16 *);
+
+
+/* Generic write error message; there is no gnu lib api to write to StdErr
+ * For now, everything goes ConOut
+ */
+void efi_printerr(
+ CHAR16 *fmt,
+ ...
+ )
+{
+ va_list args;
+ va_start (args, fmt);
+ VPrint (fmt, args);
+ va_end (args);
+}
+
+/* Simple console logger of efi-specific error messages. It uses
+ * gnu-efi library Print function to do the job.
+ */
+
+void efi_perror(CHAR16 *prog)
+{
+ /* Ensure that the err number lies within range
+ * Beware: unsigned comparisons fail on efi, signed comparisons work
+ */
+ if (EFI_ERROR(efi_errno) && (INTN)efi_errno < (INTN)nerrs)
+ efi_printerr(L"%s: %s\n", prog, uefi_errmsg[efi_errno]);
+}
+
+/* Write to UEFI ConOut */
+void efi_printout(
+ CHAR16 *fmt,
+ ...
+ )
+{
+ va_list args;
+ va_start (args, fmt);
+ VPrint (fmt, args);
+ va_end (args);
+}
+
+/* IMPORTANT:
+ * efi_setvol_root() needs to be called from efi main.
+ * The rest of the ADV support relies on the file i/o environment
+ * setup here. In order to use the EFI file support, we need
+ * to set up the volume root. Subsequent file operations need the root to
+ * access the interface routines.
+ *
+ */
+
+EFI_STATUS efi_set_volroot(EFI_HANDLE device_handle)
+{
+ vol_root = LibOpenRoot(device_handle);
+ if (!vol_root) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/* File operations using EFI runtime services */
+
+/* Open the file using EFI runtime service
+ * Opening a file in EFI requires a handle to the device
+ * root in order to use the interface to the file operations supported by UEFI.
+ * For now, assume device volume root handle from the loaded image
+ *
+ * Return a valid handle if open succeeded and null otherwise.
+ * UEFI returns a bogus handle on error, so return null handle on error.
+ *
+ * TODO:
+ * 1. Validate the assumption about the root device
+ * 2. Can EFI open a file with full path name specification?
+ * 3. Look into gnu-efi helper functions for dealing with device path/file path
+ * 4. Consider utilizing EFI file open attributes.
+ * 5. In EFI, file attributes can be specified only at the time of creation.
+ * How do we support the equivalent of set_attributes() and clear_attributes()
+ */
+EFI_FILE_HANDLE efi_open(CHAR16 *file, UINT64 mode)
+{
+ /* initialize with NULL handle since EFI open returns bogus */
+ EFI_FILE_HANDLE fd = NULL;
+
+ ASSERT(vol_root);
+
+ /* Note that the attributes parameter is none for now */
+ efi_errno = uefi_call_wrapper(vol_root->Open,
+ 5,
+ vol_root,
+ &fd,
+ file,
+ mode,
+ 0);
+ return fd;
+}
+
+/*
+ * read/write wrapper functions for UEFI
+ *
+ * Read or write the specified number of bytes starting at the
+ * offset specified.
+ *
+ * Returns:
+ * number of bytes read/written on success
+ * -1 on error
+ */
+/* Wrapper function to read from a file */
+size_t efi_xpread(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset)
+{
+ ASSERT(fd);
+ efi_errno = uefi_call_wrapper(fd->SetPosition,
+ 2,
+ fd,
+ offset);
+ if (EFI_ERROR(efi_errno)) return -1;
+ efi_errno = uefi_call_wrapper(fd->Read,
+ 3,
+ fd,
+ &count,
+ buf);
+ if (EFI_ERROR(efi_errno)) return -1;
+ return count;
+}
+
+/* Wrapper function to write */
+size_t efi_xpwrite(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset)
+{
+ ASSERT(fd);
+ efi_errno = uefi_call_wrapper(fd->SetPosition,
+ 2,
+ fd,
+ offset);
+ if (EFI_ERROR(efi_errno)) return -1;
+ efi_errno = uefi_call_wrapper(fd->Write,
+ 3,
+ fd,
+ &count,
+ buf);
+ if (EFI_ERROR(efi_errno)) return -1;
+ return count;
+}
+
+/* For an open handle, return the generic file info excluding
+ * the variable-length filename in the EFI_FILE_INFO structure.
+ */
+int efi_fstat(EFI_FILE_HANDLE fd, EFI_FILE_INFO *st)
+{
+ EFI_FILE_INFO *finfo;
+
+ ASSERT(fd);
+ finfo = LibFileInfo(fd);
+ if (finfo) {
+ uefi_call_wrapper(BS->CopyMem, 3, (VOID *)st, (VOID *)finfo, SIZE_OF_EFI_FILE_INFO);
+ FreePool(finfo);
+ return 0;
+ }
+ /* gnu-efi lib does not return EFI status; export a generic device error for now */
+ efi_errno = EFI_DEVICE_ERROR;
+ return -1;
+}
+
+/* set/clear_attributes()
+ * Currently handles only VFAT filesystem
+ * TODO:
+ * 1. Assumes VFAT file system.
+ * 2. How do we support other file systems?
+ */
+void efi_set_attributes(EFI_FILE_HANDLE fd)
+{
+ EFI_FILE_INFO *finfo;
+
+ ASSERT(fd);
+ finfo = LibFileInfo(fd);
+ if (finfo) {
+ /* Hidden+System+Readonly */
+ finfo->Attribute = EFI_FILE_READ_ONLY|EFI_FILE_HIDDEN|EFI_FILE_SYSTEM;
+ efi_errno = uefi_call_wrapper(fd->SetInfo,
+ 4,
+ fd,
+ &GenericFileInfo,
+ finfo->Size,
+ finfo);
+ FreePool(finfo);
+ } else efi_errno = EFI_NOT_FOUND;
+}
+
+void efi_clear_attributes(EFI_FILE_HANDLE fd)
+{
+ EFI_FILE_INFO *finfo;
+
+ ASSERT(fd);
+ finfo = LibFileInfo(fd);
+ if (finfo) {
+ finfo->Attribute = 0; /* no attributes */
+ efi_errno = uefi_call_wrapper(fd->SetInfo,
+ 4,
+ fd,
+ &GenericFileInfo,
+ finfo->Size,
+ finfo);
+ FreePool(finfo);
+ } else efi_errno = EFI_NOT_FOUND;
+}
+
+/* Implement the sync operation using the EFI Flush file operation*/
+void efi_sync(EFI_FILE_HANDLE fd)
+{
+ ASSERT(fd);
+ efi_errno = uefi_call_wrapper(fd->Flush, 1, fd);
+ return;
+}
+
+/* Close the file */
+void efi_close(EFI_FILE_HANDLE fd)
+{
+
+ ASSERT(fd);
+ efi_errno = uefi_call_wrapper(fd->Close, 1, fd);
+ return;
+}
diff --git a/efi/fio.h b/efi/fio.h
new file mode 100644
index 00000000..65fff8df
--- /dev/null
+++ b/efi/fio.h
@@ -0,0 +1,43 @@
+#ifndef _H_EFI_FIO_
+#define _H_EFI_FIO_
+
+/*
+ * Friendly interfaces for EFI file I/O and various EFI support functions
+ */
+
+/* MAX_EFI_ARGS - command line args for EFI executable
+ * WS(c16) - check for CHAR16 white space
+ */
+#define MAX_EFI_ARGS 64
+#define WS(c16) (c16 == L' ' || c16 == CHAR_TAB)
+
+/* VPrint is not in export declarations in gnu-efi lib yet
+ * although it is a global function; declare it here
+ */
+extern UINTN
+VPrint (
+ IN CHAR16 *fmt,
+ va_list args
+ );
+
+extern EFI_STATUS efi_errno;
+
+void efi_memcpy(unsigned char *dst, unsigned char *src, size_t len);
+void efi_memmove(unsigned char *dst, unsigned char *src, size_t len);
+void efi_memset(unsigned char *dst, unsigned char val, size_t len);
+void *efi_alloc(int size);
+void efi_free(void *ptr);
+void efi_perror(CHAR16 *str);
+void efi_printerr(IN CHAR16 *fmt, ...);
+void efi_printout(IN CHAR16 *fmt, ...);
+EFI_STATUS efi_set_volroot(EFI_HANDLE device_handle);
+EFI_FILE_HANDLE efi_open(CHAR16 *file, UINT64 mode);
+void efi_close(EFI_FILE_HANDLE fd);
+void efi_sync(EFI_FILE_HANDLE fd);
+size_t efi_xpread(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset);
+size_t efi_xpwrite(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset);
+int efi_fstat(EFI_FILE_HANDLE fd, EFI_FILE_INFO *st);
+void efi_set_attributes(EFI_FILE_HANDLE fd);
+void efi_clear_attributes(EFI_FILE_HANDLE fd);
+
+#endif
diff --git a/efi/i386/syslinux.ld b/efi/i386/syslinux.ld
new file mode 100644
index 00000000..e0270537
--- /dev/null
+++ b/efi/i386/syslinux.ld
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0;
+ ImageBase = .; /* For gnu-efi's crt0 */
+ __module_start = .;
+ . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
+ .text : {
+ FILL(0x90909090)
+ __text_start = .;
+ *(.text)
+ *(.text.*)
+ __text_end = .;
+ }
+
+ . = ALIGN(16);
+
+ .rodata : {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ __rodata_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .ctors : {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctors_end = .;
+ }
+
+ .dtors : {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __dtors_end = .;
+ }
+
+ . = ALIGN(4096);
+ .rel : {
+ *(.rel.got)
+ *(.rel.data)
+ *(.rel.data.*)
+ *(.rel.ctors)
+ }
+
+ . = ALIGN(4);
+
+ .gnu.hash : {
+ __gnu_hash_start = .;
+ *(.gnu.hash)
+ __gnu_hash_end = .;
+ }
+
+
+ .dynsym : {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynstr : {
+ __dynstr_start = .;
+ *(.dynstr)
+ __dynstr_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynlink : {
+ __dynlink_start = .;
+ *(.dynlink)
+ __dynlink_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .got : {
+ __got_start = .;
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynamic : {
+ __dynamic_start = .;
+ *(.dynamic)
+ __dynamic_end = .;
+ }
+
+ . = ALIGN(16);
+
+ .data : {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ *(.lowmem)
+ __data_end = .;
+ }
+
+ .reloc : {
+ *(.reloc)
+ }
+
+ .comment : {
+ *(.commet)
+ }
+
+ .symtab : {
+ *(.symtab)
+ }
+
+ .strtab : {
+ *(.strtab)
+ }
+
+ .bss : {
+ /* the EFI loader doesn't seem to like a .bss section,
+ so we stick it all into .data: */
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(.bss16)
+ *(.hugebss)
+ *(COMMON)
+ __bss_end = .;
+ *(.sbss)
+ *(.scommon)
+ }
+ __bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+ __bss_dwords = (__bss_len + 3) >> 2;
+
+ . = ALIGN(128);
+
+ /* Very large objects which don't need to be zeroed */
+
+ .hugebss : {
+ __hugebss_start = .;
+ *(.hugebss)
+ *(.hugebss.*)
+ __hugebss_end = .;
+ }
+
+ _end = .;
+
+ /* Stuff we don't need... */
+ /DISCARD/ : {
+ *(.eh_frame)
+ }
+}
diff --git a/efi/main.c b/efi/main.c
new file mode 100644
index 00000000..f98d95c3
--- /dev/null
+++ b/efi/main.c
@@ -0,0 +1,786 @@
+#include <core.h>
+#include <fs.h>
+#include <com32.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
+#include <syslinux/linux.h>
+#include <sys/ansi.h>
+
+#include "efi.h"
+#include "fio.h"
+
+char KernelName[FILENAME_MAX];
+uint16_t PXERetry;
+char copyright_str[] = "Copyright (C) 2011\n";
+uint8_t SerialNotice = 1;
+char syslinux_banner[] = "Syslinux 5.x (EFI)\n";
+char CurrentDirName[FILENAME_MAX];
+struct com32_sys_args __com32;
+
+uint32_t _IdleTimer = 0;
+uint16_t NoHalt = 0;
+char __lowmem_heap[32];
+uint32_t BIOS_timer_next;
+uint32_t timer_irq;
+uint8_t KbdMap[256];
+uint16_t VGAFontSize = 16;
+char aux_seg[256];
+uint8_t UserFont = 0;
+
+#undef kaboom
+void kaboom(void)
+{
+}
+
+void comboot_cleanup_api(void)
+{
+}
+
+void printf_init(void)
+{
+}
+
+void local_boot16(void)
+{
+}
+
+void bios_timer_cleanup(void)
+{
+}
+
+char trackbuf[4096];
+
+void __cdecl core_farcall(uint32_t c, const com32sys_t *a, com32sys_t *b)
+{
+}
+
+struct firmware *firmware = NULL;
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+char core_xfer_buf[65536];
+struct iso_boot_info {
+ uint32_t pvd; /* LBA of primary volume descriptor */
+ uint32_t file; /* LBA of boot file */
+ uint32_t length; /* Length of boot file */
+ uint32_t csum; /* Checksum of boot file */
+ uint32_t reserved[10]; /* Currently unused */
+} iso_boot_info;
+
+struct ip_info {
+ uint32_t ipv4;
+ uint32_t myip;
+ uint32_t serverip;
+ uint32_t gateway;
+ uint32_t netmask;
+} IPInfo;
+
+uint8_t DHCPMagic;
+uint32_t RebootTime;
+
+void pxenv(void)
+{
+}
+
+const char numIPAppends[4];
+const uint16_t IPAppends[32];
+uint16_t BIOS_fbm = 1;
+far_ptr_t InitStack;
+char StackBuf[4096];
+uint16_t APIVer;
+far_ptr_t PXEEntry;
+unsigned int __bcopyxx_len = 0;
+
+void gpxe_unload(void)
+{
+}
+
+void do_idle(void)
+{
+}
+
+void pxe_int1a(void)
+{
+}
+
+uint8_t KeepPXE;
+
+
+volatile uint32_t __ms_timer = 0xdeadbeef;
+volatile uint32_t __jiffies = 0;
+
+static UINTN cursor_x, cursor_y;
+static void efi_erase(const struct term_state *st,
+ int x0, int y0, int x1, int y1)
+{
+ SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+ cursor_x = cursor_y = 0;
+ /* Really clear the screen */
+ uefi_call_wrapper(out->ClearScreen, 1, out);
+}
+
+static void efi_write_char(uint8_t ch, uint8_t attribute)
+{
+ SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+ uint16_t c[2];
+
+ c[0] = ch;
+ c[1] = '\0';
+ uefi_call_wrapper(out->OutputString, 2, out, c);
+}
+
+static void efi_showcursor(const struct term_state *st)
+{
+ SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+ uefi_call_wrapper(out->SetCursorPosition, 3, out, cursor_x, cursor_y);
+}
+
+static void efi_set_cursor(int x, int y, bool visible)
+{
+ SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+
+ if (visible) {
+ uefi_call_wrapper(out->SetCursorPosition, 3, out, x, y);
+ cursor_x = x;
+ cursor_y = y;
+ } else
+ uefi_call_wrapper(out->EnableCursor, 2, out, false);
+}
+
+static void efi_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
+{
+}
+
+
+static void efi_get_mode(int *cols, int *rows)
+{
+ SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+ UINTN c, r;
+
+ /* XXX: Assume we're at 80x25 for now (mode 0) */
+ uefi_call_wrapper(out->QueryMode, 4, out, 0, &c, &r);
+ *rows = r;
+ *cols = c;
+}
+
+static void efi_set_mode(uint16_t mode)
+{
+}
+
+static void efi_get_cursor(int *x, int *y)
+{
+ *x = cursor_x;
+ *y = cursor_y;
+}
+
+struct output_ops efi_ops = {
+ .erase = efi_erase,
+ .write_char = efi_write_char,
+ .showcursor = efi_showcursor,
+ .set_cursor = efi_set_cursor,
+ .scroll_up = efi_scroll_up,
+ .get_mode = efi_get_mode,
+ .set_mode = efi_set_mode,
+ .get_cursor = efi_get_cursor,
+};
+
+char SubvolName[2];
+static inline EFI_MEMORY_DESCRIPTOR *
+get_memory_map(UINTN *nr_entries, UINTN *key, UINTN *desc_sz,
+ uint32_t *desc_ver)
+{
+ return LibMemoryMap(nr_entries, key, desc_sz, desc_ver);
+}
+
+
+int efi_scan_memory(scan_memory_callback_t callback, void *data)
+{
+ UINTN nr_entries, key, desc_sz;
+ UINTN buf;
+ UINT32 desc_ver;
+ int rv = 0;
+ int i;
+
+ buf = (UINTN)get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+ if (!buf)
+ return -1;
+
+ for (i = 0; i < nr_entries; buf += desc_sz, i++) {
+ EFI_MEMORY_DESCRIPTOR *m;
+ UINT64 region_sz;
+ int valid;
+
+ m = (EFI_MEMORY_DESCRIPTOR *)buf;
+ region_sz = m->NumberOfPages * EFI_PAGE_SIZE;
+
+ switch (m->Type) {
+ case EfiConventionalMemory:
+ valid = 1;
+ break;
+ default:
+ valid = 0;
+ break;
+ }
+
+ rv = callback(data, m->PhysicalStart, region_sz, valid);
+ if (rv)
+ break;
+ }
+
+ FreePool((void *)buf);
+ return rv;
+}
+
+extern uint16_t *bios_free_mem;
+void efi_init(void)
+{
+ /* XXX timer */
+ *bios_free_mem = 0;
+ mem_init();
+}
+
+char efi_getchar(char *hi)
+{
+ SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+ char c;
+
+ WaitForSingleEvent(in->WaitForKey, 0);
+ do {
+ status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key);
+ } while (status == EFI_NOT_READY);
+
+ c = (char)key.UnicodeChar;
+ return c;
+}
+
+int efi_pollchar(void)
+{
+ SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
+ EFI_STATUS status;
+
+ status = WaitForSingleEvent(in->WaitForKey, 1);
+ return status != EFI_TIMEOUT;
+}
+
+struct input_ops efi_iops = {
+ .getchar = efi_getchar,
+ .pollchar = efi_pollchar,
+};
+
+bool efi_ipappend_strings(char **list, int *count)
+{
+ *count = numIPAppends;
+ *list = (char *)IPAppends;
+}
+
+extern void efi_adv_init(void);
+extern int efi_adv_write(void);
+
+struct adv_ops efi_adv_ops = {
+ .init = efi_adv_init,
+ .write = efi_adv_write,
+};
+
+struct efi_info {
+ uint32_t load_signature;
+ uint32_t systab;
+ uint32_t desc_size;
+ uint32_t desc_version;
+ uint32_t memmap;
+ uint32_t memmap_size;
+ uint32_t systab_hi;
+ uint32_t memmap_hi;
+};
+
+#define E820MAX 128
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+struct e820_entry {
+ uint64_t start;
+ uint64_t len;
+ uint32_t type;
+} __packed;
+
+struct boot_params {
+ struct screen_info screen_info;
+ uint8_t _pad[0x1c0 - sizeof(struct screen_info)];
+ struct efi_info efi;
+ uint8_t _pad2[8];
+ uint8_t e820_entries;
+ uint8_t _pad3[0x2d0 - 0x1e8 - sizeof(uint8_t)];
+ struct e820_entry e820_map[E820MAX];
+} __packed;
+
+#if __SIZEOF_POINTER__ == 4
+#define EFI_LOAD_SIG "EL32"
+#elif __SIZEOF_POINTER__ == 8
+#define EFI_LOAD_SIG "EL64"
+#else
+#error "unsupported architecture"
+#endif
+
+struct dt_desc {
+ uint16_t limit;
+ uint64_t *base;
+} __packed;
+
+struct dt_desc gdt = { 0x800, 0 };
+struct dt_desc idt = { 0, 0 };
+
+static inline EFI_MEMORY_DESCRIPTOR *
+get_mem_desc(addr_t memmap, UINTN desc_sz, int i)
+{
+ return (EFI_MEMORY_DESCRIPTOR *)(memmap + (i * desc_sz));
+}
+
+EFI_HANDLE image_handle;
+
+static inline UINT64 round_up(UINT64 x, UINT64 y)
+{
+ return (((x - 1) | (y - 1)) + 1);
+}
+
+static inline UINT64 round_down(UINT64 x, UINT64 y)
+{
+ return (x & ~(y - 1));
+}
+
+static void find_addr(EFI_PHYSICAL_ADDRESS *first,
+ EFI_PHYSICAL_ADDRESS *last,
+ EFI_PHYSICAL_ADDRESS min,
+ EFI_PHYSICAL_ADDRESS max,
+ size_t size, size_t align)
+{
+ EFI_MEMORY_DESCRIPTOR *map;
+ EFI_STATUS status;
+ UINT32 desc_ver;
+ UINTN nr_entries, key, desc_sz;
+ UINT64 addr;
+ int i;
+
+ map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+ if (!map)
+ return;
+
+ for (i = 0; i < nr_entries; i++) {
+ EFI_MEMORY_DESCRIPTOR *m;
+ EFI_PHYSICAL_ADDRESS best;
+ UINT64 start, end;
+
+ m = get_mem_desc((addr_t)map, desc_sz, i);
+ if (m->Type != EfiConventionalMemory)
+ continue;
+
+ if (m->NumberOfPages < EFI_SIZE_TO_PAGES(size))
+ continue;
+
+ start = m->PhysicalStart;
+ end = m->PhysicalStart + (m->NumberOfPages << EFI_PAGE_SHIFT);
+ if (first) {
+ if (end < min)
+ continue;
+
+ /* What's the best address? */
+ if (start < min && min < end)
+ best = min;
+ else
+ best = m->PhysicalStart;
+
+ start = round_up(best, align);
+ if (start > max)
+ continue;
+
+ /* Have we run out of space in this region? */
+ if (end < start || (start + size) > end)
+ continue;
+
+ if (start < *first)
+ *first = start;
+ }
+
+ if (last) {
+ if (start > max)
+ continue;
+
+ /* What's the best address? */
+ if (start < max && max < end)
+ best = max - size;
+ else
+ best = end - size;
+
+ start = round_down(best, align);
+ if (start < min || start < m->PhysicalStart)
+ continue;
+
+ if (start > *last)
+ *last = start;
+ }
+ }
+
+ FreePool(map);
+}
+
+static EFI_STATUS allocate_addr(EFI_PHYSICAL_ADDRESS *addr, size_t size)
+{
+ UINTN npages = EFI_SIZE_TO_PAGES(size);
+
+ return uefi_call_wrapper(BS->AllocatePages, 4,
+ AllocateAddress,
+ EfiLoaderData, npages,
+ addr);
+}
+
+static void free_addr(EFI_PHYSICAL_ADDRESS addr, size_t size)
+{
+ UINTN npages = EFI_SIZE_TO_PAGES(size);
+
+ uefi_call_wrapper(BS->FreePages, 2, addr, npages);
+}
+
+int efi_boot_linux(void *kernel_buf, size_t kernel_size,
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
+{
+ EFI_MEMORY_DESCRIPTOR *map;
+ struct linux_header *hdr;
+ struct boot_params *bp;
+ struct screen_info *si;
+ struct e820_entry *e820buf, *e;
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS first, last;
+ UINTN nr_entries, key, desc_sz;
+ UINT32 desc_ver;
+ uint32_t e820_type;
+ addr_t irf_size;
+ int i;
+
+ hdr = (struct linux_header *)kernel_buf;
+ bp = (struct boot_params *)hdr;
+
+ /*
+ * We require a relocatable kernel because we have no control
+ * over free memory in the memory map.
+ */
+ if (hdr->version < 0x20a || !hdr->relocatable_kernel) {
+ printf("bzImage version unsupported\n");
+ goto bail;
+ }
+
+ hdr->type_of_loader = 0x30; /* SYSLINUX unknown module */
+ hdr->cmd_line_ptr = cmdline;
+
+ si = &bp->screen_info;
+ memset(si, 0, sizeof(*si));
+ setup_screen(si);
+
+#if __SIZEOF_POINTER__ == 4
+ gdt.base = (uint16_t *)malloc(gdt.limit);
+#elif __SIZEOF_POINTER__ == 8
+ gdt.base = (uint64_t *)malloc(gdt.limit);
+#else
+#error "unsupported architecture"
+#endif
+ memset(gdt.base, 0x0, gdt.limit);
+
+ first = -1ULL;
+ find_addr(&first, NULL, 0x1000, -1ULL, kernel_size,
+ hdr->kernel_alignment);
+ if (first != -1ULL) {
+ status = allocate_addr(&first, kernel_size);
+ }
+
+ if (first == -1ULL || status != EFI_SUCCESS) {
+ printf("Failed to allocate memory for kernel\n");
+ goto bail;
+ }
+
+#if __SIZEOF_POINTER__ == 4
+ hdr->code32_start = (uint32_t)first;
+#elif __SIZEOF_POINTER__ == 8
+ hdr->code32_start = (uint32_t)(uint64_t)first;
+#else
+#error "unsupported architecture"
+#endif
+
+ /* Skip the setup headers and copy the code */
+ kernel_buf += (hdr->setup_sects + 1) * 512;
+ memcpy(hdr->code32_start, kernel_buf, kernel_size);
+
+ /*
+ * Figure out the size of the initramfs, and where to put it.
+ * We should put it at the highest possible address which is
+ * <= hdr->initrd_addr_max, which fits the entire initramfs.
+ */
+ irf_size = initramfs_size(initramfs); /* Handles initramfs == NULL */
+ if (irf_size) {
+ struct initramfs *ip;
+ addr_t next_addr, len, pad;
+
+ last = 0;
+ find_addr(NULL, &last, 0x1000, hdr->initrd_addr_max,
+ irf_size, INITRAMFS_MAX_ALIGN);
+ if (last)
+ status = allocate_addr(&last, irf_size);
+
+ if (!last || status != EFI_SUCCESS) {
+ printf("Failed to allocate initramfs memory\n");
+ goto free_kernel;
+ }
+
+ hdr->ramdisk_image = (uint32_t)last;
+ hdr->ramdisk_size = irf_size;
+
+ /* Copy initramfs into allocated memory */
+ for (ip = initramfs->next; ip->len; ip = ip->next) {
+ len = ip->len;
+ next_addr = last + len;
+
+ /*
+ * If this isn't the last entry, extend the
+ * zero-pad region to enforce the alignment of
+ * the next chunk.
+ */
+ if (ip->next->len) {
+ pad = -next_addr & (ip->next->align - 1);
+ len += pad;
+ next_addr += pad;
+ }
+
+ if (ip->data_len)
+ memcpy(last, ip->data, ip->data_len);
+
+ if (len > ip->data_len)
+ memset(last + ip->data_len, 0,
+ len - ip->data_len);
+
+ last = next_addr;
+ }
+ }
+
+ /* Build efi memory map */
+ map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+ if (!map)
+ goto free_irf;
+
+#if __SIZEOF_POINTER__ == 4
+ bp->efi.memmap = map;
+ bp->efi.memmap_size = nr_entries * desc_sz;
+
+ bp->efi.systab = ST;
+ bp->efi.desc_size = desc_sz;
+ bp->efi.desc_version = desc_ver;
+#elif __SIZEOF_POINTER__ == 8
+ bp->efi.memmap = (uint32_t)(unsigned long)map;
+ bp->efi.memmap_hi = ((unsigned long)map) >> 32;
+ bp->efi.memmap_size = nr_entries * desc_sz;
+
+ bp->efi.systab = (uint32_t)(unsigned long)ST;
+ bp->efi.systab_hi = ((unsigned long)ST) >> 32;
+ bp->efi.desc_size = desc_sz;
+ bp->efi.desc_version = desc_ver;
+#else
+#error "unsupported architecture"
+#endif
+
+ /*
+ * Even though 'memmap' contains the memory map we provided
+ * previously in efi_scan_memory(), we should recalculate the
+ * e820 map because it will most likely have changed in the
+ * interim.
+ */
+ e = e820buf = bp->e820_map;
+ for (i = 0; i < nr_entries && i < E820MAX; i++) {
+ struct e820_entry *prev = NULL;
+
+ if (e > e820buf)
+ prev = e - 1;
+
+ map = get_mem_desc(bp->efi.memmap, desc_sz, i);
+ e->start = map->PhysicalStart;
+ e->len = map->NumberOfPages << EFI_PAGE_SHIFT;
+
+ switch (map->Type) {
+ case EfiReservedMemoryType:
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ case EfiPalCode:
+ e820_type = E820_RESERVED;
+ break;
+
+ case EfiUnusableMemory:
+ e820_type = E820_UNUSABLE;
+ break;
+
+ case EfiACPIReclaimMemory:
+ e820_type = E820_ACPI;
+ break;
+
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ e820_type = E820_RAM;
+ break;
+
+ case EfiACPIMemoryNVS:
+ e820_type = E820_NVS;
+ break;
+ default:
+ continue;
+ }
+
+ e->type = e820_type;
+
+ /* Check for adjacent entries we can merge. */
+ if (prev && (prev->start + prev->len) == e->start &&
+ prev->type == e->type)
+ prev->len += e->len;
+ else
+ e++;
+ }
+
+ bp->e820_entries = e - e820buf;
+
+ status = uefi_call_wrapper(BS->ExitBootServices, 2, image_handle, key);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to exit boot services: 0x%016lx\n", status);
+ goto free_map;
+ }
+
+ memcpy(&bp->efi.load_signature, EFI_LOAD_SIG, sizeof(uint32_t));
+
+ /*
+ * 4Gb - (0x100000*0x1000 = 4Gb)
+ * base address=0
+ * code read/exec
+ * granularity=4096, 386 (+5th nibble of limit)
+ */
+ gdt.base[2] = 0x00cf9a000000ffff;
+
+ /*
+ * 4Gb - (0x100000*0x1000 = 4Gb)
+ * base address=0
+ * data read/write
+ * granularity=4096, 386 (+5th nibble of limit)
+ */
+ gdt.base[3] = 0x00cf92000000ffff;
+
+ /* Task segment value */
+ gdt.base[4] = 0x0080890000000000;
+
+ asm volatile ("lidt %0" :: "m" (idt));
+ asm volatile ("lgdt %0" :: "m" (gdt));
+
+#if __SIZEOF_POINTER__ == 4
+ asm volatile ("cli \n"
+ "movl %0, %%esi \n"
+ "movl %1, %%ecx \n"
+ "jmp *%%ecx \n"
+ :: "m" (bp), "m" (hdr->code32_start));
+#elif __SIZEOF_POINTER__ == 8
+ {
+ struct {
+ uint32_t kernel_entry;
+ uint16_t kernel_cs;
+ } kernel_vector;
+ void *kstart;
+
+ kernel_vector.kernel_entry = hdr->code32_start;
+ kernel_vector.kernel_cs = 0x10;
+ kstart = (VOID *)&kernel_vector;
+ asm volatile ("cli \n"
+ "mov %0, %%rsi \n"
+ "mov %1, %%rcx \n"
+ "ljmp *(%%rcx) \n"
+ :: "m" (bp), "m" (kstart));
+ }
+#else
+#error "unsupported architecture"
+#endif
+ /* NOTREACHED */
+
+free_map:
+ FreePool(map);
+free_irf:
+ if (irf_size)
+ free_addr(last, irf_size);
+free_kernel:
+ free_addr(first, kernel_size);
+bail:
+ return -1;
+}
+
+extern struct disk *efi_disk_init(EFI_HANDLE);
+extern void serialcfg(uint16_t *, uint16_t *, uint16_t *);
+
+struct firmware efi_fw = {
+ .init = efi_init,
+ .scan_memory = efi_scan_memory,
+ .disk_init = efi_disk_init,
+ .o_ops = &efi_ops,
+ .i_ops = &efi_iops,
+ .get_serial_console_info = serialcfg,
+ .ipappend_strings = efi_ipappend_strings,
+ .adv_ops = &efi_adv_ops,
+ .boot_linux = efi_boot_linux,
+};
+
+static inline void syslinux_register_efi(void)
+{
+ firmware = &efi_fw;
+}
+
+extern void init(void);
+extern const struct fs_ops vfat_fs_ops;
+
+char free_high_memory[4096];
+
+extern char __bss_start[];
+extern char __bss_end[];
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table)
+{
+ EFI_LOADED_IMAGE *info;
+ EFI_STATUS status = EFI_SUCCESS;
+ const struct fs_ops *ops[] = { &vfat_fs_ops, NULL };
+ unsigned long len = (unsigned long)__bss_end - (unsigned long)__bss_start;
+ static struct disk_private priv;
+
+ memset(__bss_start, 0, len);
+ InitializeLib(image, table);
+
+ image_handle = image;
+ syslinux_register_efi();
+ init();
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
+ &LoadedImageProtocol, (void **)&info);
+ if (status != EFI_SUCCESS) {
+ Print(L"Failed to lookup LoadedImageProtocol\n");
+ goto out;
+ }
+
+ /* Use device handle to set up the volume root to proceed with ADV init */
+ if (EFI_ERROR(efi_set_volroot(info->DeviceHandle))) {
+ Print(L"Failed to locate root device to prep for file operations & ADV initialization\n");
+ goto out;
+ }
+
+ /* TODO: once all errors are captured in efi_errno, bail out if necessary */
+
+ /* XXX figure out what file system we're on */
+ priv.dev_handle = info->DeviceHandle;
+ fs_init(ops, &priv);
+ load_env32();
+
+out:
+ return status;
+}
diff --git a/efi/syslinux.ld b/efi/syslinux.ld
new file mode 100644
index 00000000..e0270537
--- /dev/null
+++ b/efi/syslinux.ld
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0;
+ ImageBase = .; /* For gnu-efi's crt0 */
+ __module_start = .;
+ . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
+ .text : {
+ FILL(0x90909090)
+ __text_start = .;
+ *(.text)
+ *(.text.*)
+ __text_end = .;
+ }
+
+ . = ALIGN(16);
+
+ .rodata : {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ __rodata_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .ctors : {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctors_end = .;
+ }
+
+ .dtors : {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __dtors_end = .;
+ }
+
+ . = ALIGN(4096);
+ .rel : {
+ *(.rel.got)
+ *(.rel.data)
+ *(.rel.data.*)
+ *(.rel.ctors)
+ }
+
+ . = ALIGN(4);
+
+ .gnu.hash : {
+ __gnu_hash_start = .;
+ *(.gnu.hash)
+ __gnu_hash_end = .;
+ }
+
+
+ .dynsym : {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynstr : {
+ __dynstr_start = .;
+ *(.dynstr)
+ __dynstr_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynlink : {
+ __dynlink_start = .;
+ *(.dynlink)
+ __dynlink_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .got : {
+ __got_start = .;
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynamic : {
+ __dynamic_start = .;
+ *(.dynamic)
+ __dynamic_end = .;
+ }
+
+ . = ALIGN(16);
+
+ .data : {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ *(.lowmem)
+ __data_end = .;
+ }
+
+ .reloc : {
+ *(.reloc)
+ }
+
+ .comment : {
+ *(.commet)
+ }
+
+ .symtab : {
+ *(.symtab)
+ }
+
+ .strtab : {
+ *(.strtab)
+ }
+
+ .bss : {
+ /* the EFI loader doesn't seem to like a .bss section,
+ so we stick it all into .data: */
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(.bss16)
+ *(.hugebss)
+ *(COMMON)
+ __bss_end = .;
+ *(.sbss)
+ *(.scommon)
+ }
+ __bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+ __bss_dwords = (__bss_len + 3) >> 2;
+
+ . = ALIGN(128);
+
+ /* Very large objects which don't need to be zeroed */
+
+ .hugebss : {
+ __hugebss_start = .;
+ *(.hugebss)
+ *(.hugebss.*)
+ __hugebss_end = .;
+ }
+
+ _end = .;
+
+ /* Stuff we don't need... */
+ /DISCARD/ : {
+ *(.eh_frame)
+ }
+}
diff --git a/efi/wrapper.c b/efi/wrapper.c
new file mode 100644
index 00000000..0943534c
--- /dev/null
+++ b/efi/wrapper.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2011 Intel Corporation; author Matt Fleming
+ *
+ * Wrap the ELF shared library in a PE32 (32bit) or PE32+ (64bit) suit.
+ *
+ * Syslinux plays some games with the ELF sections that are not easily
+ * converted to a PE32 executable. For instance, Syslinux requires
+ * that a symbol hash table be present (GNU hash or SysV) so that
+ * symbols in ELF modules can be resolved at runtime but the EFI
+ * firmware loader doesn't like that and refuses to load the file.
+ *
+ * We pretend that we have an EFI executable with a single .text
+ * section so that the EFI loader will load it and jump to the entry
+ * point. Once the Syslinux ELF shared object has control we can do
+ * whatever we want.
+ */
+#include <linux/elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "wrapper.h"
+
+#if __SIZEOF_POINTER__ == 4
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Addr Elf_Addr;
+#elif __SIZEOF_POINTER__ == 8
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Addr Elf_Addr;
+#else
+#error "unsupported architecture"
+#endif
+
+/*
+ * 'so_size' is the file size of the ELF shared object.
+ * 'class' dictates how the header is written
+ * For 32bit machines (class == ELFCLASS32), the optional
+ * header includes PE32 header fields
+ * For 64bit machines (class == ELFCLASS64), the optional
+ * header includes PE32+header fields
+ */
+static void write_header(FILE *f, __uint32_t entry, __uint32_t so_size, __uint8_t class)
+{
+ struct optional_hdr o_hdr;
+ struct optional_hdr_pe32p o_hdr_pe32p;
+ struct section t_sec, r_sec;
+ struct extra_hdr e_hdr;
+ struct extra_hdr_pe32p e_hdr_pe32p;
+ struct coff_hdr c_hdr;
+ struct header hdr;
+ struct coff_reloc c_rel;
+ __uint32_t total_sz = so_size;
+ __uint32_t dummy = 0;
+ __uint32_t hdr_sz;
+ __uint32_t reloc_start, reloc_end;
+
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msdos_signature = MSDOS_SIGNATURE;
+ hdr.pe_hdr = OFFSETOF(struct header, pe_signature);
+ hdr.pe_signature = PE_SIGNATURE;
+ fwrite(&hdr, sizeof(hdr), 1, f);
+
+ memset(&c_hdr, 0, sizeof(c_hdr));
+ c_hdr.nr_sections = 2;
+ c_hdr.nr_syms = 1;
+ if (class == ELFCLASS32) {
+ hdr_sz = sizeof(o_hdr) + sizeof(t_sec) + sizeof(e_hdr) +
+ sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
+ + sizeof(dummy);
+ total_sz += hdr_sz;
+ entry += hdr_sz;
+ c_hdr.arch = IMAGE_FILE_MACHINE_I386;
+ c_hdr.characteristics = IMAGE_FILE_32BIT_MACHINE |
+ IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
+ IMAGE_FILE_LINE_NUMBERS_STRIPPED;
+ c_hdr.optional_hdr_sz = sizeof(o_hdr) + sizeof(e_hdr);
+ fwrite(&c_hdr, sizeof(c_hdr), 1, f);
+ memset(&o_hdr, 0, sizeof(o_hdr));
+ o_hdr.format = PE32_FORMAT;
+ o_hdr.major_linker_version = 0x02;
+ o_hdr.minor_linker_version = 0x14;
+ o_hdr.code_sz = total_sz;
+ o_hdr.entry_point = entry;
+ fwrite(&o_hdr, sizeof(o_hdr), 1, f);
+ memset(&e_hdr, 0, sizeof(e_hdr));
+ e_hdr.section_align = 4096;
+ e_hdr.file_align = 512;
+ e_hdr.image_sz = total_sz;
+ e_hdr.headers_sz = 512;
+ e_hdr.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+ e_hdr.rva_and_sizes_nr = 1;
+ fwrite(&e_hdr, sizeof(e_hdr), 1, f);
+ }
+ else if (class == ELFCLASS64) {
+ hdr_sz = sizeof(o_hdr_pe32p) + sizeof(t_sec) + sizeof(e_hdr_pe32p) +
+ sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
+ + sizeof(dummy);
+ total_sz += hdr_sz;
+ entry += hdr_sz;
+ c_hdr.arch = IMAGE_FILE_MACHINE_X86_64;
+ c_hdr.characteristics = IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
+ IMAGE_FILE_LINE_NUMBERS_STRIPPED;
+ c_hdr.optional_hdr_sz = sizeof(o_hdr_pe32p) + sizeof(e_hdr_pe32p);
+ fwrite(&c_hdr, sizeof(c_hdr), 1, f);
+ memset(&o_hdr_pe32p, 0, sizeof(o_hdr_pe32p));
+ o_hdr_pe32p.format = PE32P_FORMAT;
+ o_hdr_pe32p.major_linker_version = 0x02;
+ o_hdr_pe32p.minor_linker_version = 0x14;
+ o_hdr_pe32p.code_sz = total_sz;
+ o_hdr_pe32p.entry_point = entry;
+ fwrite(&o_hdr_pe32p, sizeof(o_hdr_pe32p), 1, f);
+ memset(&e_hdr_pe32p, 0, sizeof(e_hdr));
+ e_hdr_pe32p.section_align = 4096;
+ e_hdr_pe32p.file_align = 512;
+ e_hdr_pe32p.image_sz = total_sz;
+ e_hdr_pe32p.headers_sz = 512;
+ e_hdr_pe32p.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+ e_hdr_pe32p.rva_and_sizes_nr = 1;
+ fwrite(&e_hdr_pe32p, sizeof(e_hdr_pe32p), 1, f);
+ }
+
+ memset(&t_sec, 0, sizeof(t_sec));
+ strcpy((char *)t_sec.name, ".text");
+ t_sec.virtual_sz = total_sz;
+ t_sec.raw_data_sz = total_sz;
+ t_sec.characteristics = IMAGE_SCN_CNT_CODE |
+ IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+ IMAGE_SCN_MEM_READ;
+ fwrite(&t_sec, sizeof(t_sec), 1, f);
+
+ /*
+ * Write our dummy relocation and reloc section.
+ */
+ memset(&r_sec, 0, sizeof(r_sec));
+ strcpy((char *)r_sec.name, ".reloc");
+ r_sec.virtual_sz = sizeof(c_rel);
+ r_sec.virtual_address = ftell(f) + sizeof(r_sec);
+ r_sec.raw_data_sz = r_sec.virtual_sz;
+ r_sec.raw_data = r_sec.virtual_address;
+ r_sec.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE |
+ IMAGE_SCN_MEM_READ;
+ fwrite(&r_sec, sizeof(r_sec), 1, f);
+
+ memset(&c_rel, 0, sizeof(c_rel));
+ c_rel.virtual_address = ftell(f) + sizeof(c_rel);
+ c_rel.symtab_index = 10;
+ fwrite(&c_rel, sizeof(c_rel), 1, f);
+ fwrite(&dummy, sizeof(dummy), 1, f);
+
+}
+
+static void usage(char *progname)
+{
+ fprintf(stderr, "usage: %s <ELF shared object> <output file>\n",
+ progname);
+}
+
+int main(int argc, char **argv)
+{
+ struct stat st;
+ Elf32_Ehdr e32_hdr;
+ Elf64_Ehdr e64_hdr;
+ __uint32_t entry;
+ __uint8_t class;
+ unsigned char *id;
+ FILE *f_in, *f_out;
+ void *buf;
+ size_t rv;
+
+ if (argc < 3) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ f_in = fopen(argv[1], "r");
+ if (!f_in) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(argv[1], &st) != 0) {
+ perror("stat");
+ exit(EXIT_FAILURE);
+ }
+
+ f_out = fopen(argv[2], "w");
+ if (!f_out) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Parse the ELF header and find the entry point.
+ */
+ fread((void *)&e32_hdr, sizeof(e32_hdr), 1, f_in);
+ if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ id = e32_hdr.e_ident;
+ class = ELFCLASS32;
+ entry = e32_hdr.e_entry;
+ }
+ else if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ /* read the header again for x86_64
+ * note that the elf header entry point is 64bit whereas
+ * the entry point in PE/COFF format is 32bit!*/
+ class = ELFCLASS64;
+ rewind(f_in);
+ fread((void *)&e64_hdr, sizeof(e64_hdr), 1, f_in);
+ id = e64_hdr.e_ident;
+ entry = e64_hdr.e_entry;
+ } else {
+ fprintf(stderr, "Unsupported architecture\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (id[EI_MAG0] != ELFMAG0 ||
+ id[EI_MAG1] != ELFMAG1 ||
+ id[EI_MAG2] != ELFMAG2 ||
+ id[EI_MAG3] != ELFMAG3) {
+ fprintf(stderr, "Input file not ELF shared object\n");
+ exit(EXIT_FAILURE);
+ }
+
+ buf = malloc(st.st_size);
+ if (!buf) {
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ write_header(f_out, entry, st.st_size, class);
+
+ /* Write out the entire ELF shared object */
+ rewind(f_in);
+ rv = fread(buf, st.st_size, 1, f_in);
+ if (!rv && ferror(f_in)) {
+ fprintf(stderr, "Failed to read all bytes from input\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fwrite(buf, st.st_size, rv, f_out);
+ return 0;
+}
diff --git a/efi/wrapper.h b/efi/wrapper.h
new file mode 100644
index 00000000..492c262b
--- /dev/null
+++ b/efi/wrapper.h
@@ -0,0 +1,164 @@
+#ifndef EFI_WRAPPER_H
+#define EFI_WRAPPER_H
+
+#define MSDOS_SIGNATURE 0x5a4d
+#define PE_SIGNATURE 0x4550
+#define PE32_FORMAT 0x10b
+#define PE32P_FORMAT 0x20b /* PE32+ */
+
+#define IMAGE_FILE_MACHINE_I386 0x14c
+#define IMAGE_FILE_MACHINE_X86_64 0x8664
+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
+#define IMAGE_FILE_LINE_NUMBERS_STRIPPED 0x0004
+#define IMAGE_FILE_32BIT_MACHINE 0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
+
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 0x0a
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+
+#define __packed __attribute__((packed))
+#define OFFSETOF(t,m) ((size_t)&((t *)0)->m)
+
+struct header {
+ __uint16_t msdos_signature;
+ __uint8_t _pad1[0x3c - 2];
+ __uint32_t pe_hdr;
+ __uint16_t pe_signature;
+ __uint16_t _pad2;
+} __packed;
+
+/* FIXME: when setting up coff_hdr, set up optional_hdr_sz
+ * based on PE32 or PE32+ format
+ */
+/*
+ * COFF header
+ */
+struct coff_hdr {
+ __uint16_t arch;
+ __uint16_t nr_sections;
+ __uint32_t timedatestamp;
+ __uint32_t symtab;
+ __uint32_t nr_syms;
+ __uint16_t optional_hdr_sz;
+ __uint16_t characteristics;
+} __packed;
+
+struct optional_hdr {
+ __uint16_t format;
+ __uint8_t major_linker_version;
+ __uint8_t minor_linker_version;
+ __uint32_t code_sz;
+ __uint32_t initialized_data_sz;
+ __uint32_t uninitialized_data_sz;
+ __uint32_t entry_point;
+ __uint32_t base_code;
+ __uint32_t data;
+} __packed;
+
+/* For PE32+, the optional_header does NOT have
+ * data after base_code
+ */
+struct optional_hdr_pe32p {
+ __uint16_t format;
+ __uint8_t major_linker_version;
+ __uint8_t minor_linker_version;
+ __uint32_t code_sz;
+ __uint32_t initialized_data_sz;
+ __uint32_t uninitialized_data_sz;
+ __uint32_t entry_point;
+ __uint32_t base_code;
+} __packed;
+/*
+ * Extra header fields
+ */
+struct extra_hdr {
+ __uint32_t image_base;
+ __uint32_t section_align;
+ __uint32_t file_align;
+ __uint16_t major_os_version;
+ __uint16_t minor_os_version;
+ __uint16_t major_image_version;
+ __uint16_t minor_image_version;
+ __uint16_t major_subsystem_version;
+ __uint16_t minor_subsystem_version;
+ __uint32_t win32_version;
+ __uint32_t image_sz;
+ __uint32_t headers_sz;
+ __uint32_t checksum;
+ __uint16_t subsystem;
+ __uint16_t dll_characteristics;
+ __uint32_t stack_reserve_sz;
+ __uint32_t stack_commit_sz;
+ __uint32_t heap_reserve_sz;
+ __uint32_t heap_commit_sz;
+ __uint32_t loader_flags;
+ __uint32_t rva_and_sizes_nr;
+ __uint64_t export_table;
+ __uint64_t import_table;
+ __uint64_t resource_table;
+ __uint64_t exception_table;
+ __uint64_t certification_table;
+ __uint64_t base_relocation_table;
+} __packed;
+
+/* Extra header for PE32+ format
+ * FIXME: There are additional fields in Microsoft PE COFF v8
+ */
+
+struct extra_hdr_pe32p {
+ __uint64_t image_base;
+ __uint32_t section_align;
+ __uint32_t file_align;
+ __uint16_t major_os_version;
+ __uint16_t minor_os_version;
+ __uint16_t major_image_version;
+ __uint16_t minor_image_version;
+ __uint16_t major_subsystem_version;
+ __uint16_t minor_subsystem_version;
+ __uint32_t win32_version;
+ __uint32_t image_sz;
+ __uint32_t headers_sz;
+ __uint32_t checksum;
+ __uint16_t subsystem;
+ __uint16_t dll_characteristics;
+ __uint64_t stack_reserve_sz;
+ __uint64_t stack_commit_sz;
+ __uint64_t heap_reserve_sz;
+ __uint64_t heap_commit_sz;
+ __uint32_t loader_flags;
+ __uint32_t rva_and_sizes_nr;
+ __uint64_t export_table;
+ __uint64_t import_table;
+ __uint64_t resource_table;
+ __uint64_t exception_table;
+ __uint64_t certification_table;
+ __uint64_t base_relocation_table;
+} __packed;
+
+struct section {
+ __uint8_t name[8];
+ __uint32_t virtual_sz;
+ __uint32_t virtual_address;
+ __uint32_t raw_data_sz;
+ __uint32_t raw_data;
+ __uint32_t relocs;
+ __uint32_t line_numbers;
+ __uint16_t relocs_nr;
+ __uint16_t line_numbers_nr;
+ __uint32_t characteristics;
+} __packed;
+
+struct coff_reloc {
+ __uint32_t virtual_address;
+ __uint32_t symtab_index;
+ __uint16_t type;
+};
+
+#endif /* EFI_WRAPPER_H */
diff --git a/efi/x86_64/syslinux.ld b/efi/x86_64/syslinux.ld
new file mode 100644
index 00000000..3c8c7c34
--- /dev/null
+++ b/efi/x86_64/syslinux.ld
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0;
+ ImageBase = .; /* For gnu-efi's crt0 */
+ __module_start = .;
+ . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
+ .text : {
+ FILL(0x90909090)
+ __text_start = .;
+ *(.text)
+ *(.text.*)
+ __text_end = .;
+ }
+
+ . = ALIGN(16);
+
+ .rodata : {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ __rodata_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .ctors : {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctors_end = .;
+ }
+
+ .dtors : {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __dtors_end = .;
+ }
+
+ . = ALIGN(4096);
+ .rel : {
+ *(.rel.got)
+ *(.rel.data)
+ *(.rel.data.*)
+ *(.rel.ctors)
+ }
+
+ . = ALIGN(4);
+
+ .gnu.hash : {
+ __gnu_hash_start = .;
+ *(.gnu.hash)
+ __gnu_hash_end = .;
+ }
+
+
+ .dynsym : {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynstr : {
+ __dynstr_start = .;
+ *(.dynstr)
+ __dynstr_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynlink : {
+ __dynlink_start = .;
+ *(.dynlink)
+ __dynlink_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .got : {
+ __got_start = .;
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ __got_end = .;
+ }
+
+ . = ALIGN(4);
+
+ .dynamic : {
+ __dynamic_start = .;
+ *(.dynamic)
+ __dynamic_end = .;
+ }
+
+ . = ALIGN(16);
+
+ .data : {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ *(.lowmem)
+ __data_end = .;
+ }
+
+ .reloc : {
+ *(.reloc)
+ }
+
+ .comment : {
+ *(.commet)
+ }
+
+ .symtab : {
+ *(.symtab)
+ }
+
+ .strtab : {
+ *(.strtab)
+ }
+
+ .bss : {
+ /* the EFI loader doesn't seem to like a .bss section,
+ so we stick it all into .data: */
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(.bss16)
+ *(.hugebss)
+ *(COMMON)
+ __bss_end = .;
+ *(.sbss)
+ *(.scommon)
+ }
+ __bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+ __bss_dwords = (__bss_len + 3) >> 2;
+
+ . = ALIGN(128);
+
+ /* Very large objects which don't need to be zeroed */
+
+ .hugebss : {
+ __hugebss_start = .;
+ *(.hugebss)
+ *(.hugebss.*)
+ __hugebss_end = .;
+ }
+
+ _end = .;
+
+ /* Stuff we don't need... */
+ /DISCARD/ : {
+ *(.eh_frame)
+ }
+}
diff --git a/gpxe/Makefile b/gpxe/Makefile
index 8bce8d12..fe754c62 100644
--- a/gpxe/Makefile
+++ b/gpxe/Makefile
@@ -30,7 +30,9 @@ clean: tidy
dist:
$(MAKE) -C src veryclean > /dev/null 2>&1
-spotless: clean dist
+#spotless: clean dist
+#Including 'dist' errors out for make ARCH=x86_64 spotless
+spotless: clean
rm -f $(TARGETS)
installer:
diff --git a/mbr/Makefile b/mbr/Makefile
index 993bb100..8b46452a 100644
--- a/mbr/Makefile
+++ b/mbr/Makefile
@@ -33,8 +33,9 @@ all: mbr.bin altmbr.bin gptmbr.bin isohdpfx.bin isohdppx.bin \
$(CC) $(MAKEDEPS) $(SFLAGS) -Wa,-a=$*_f.lst -DFORCE_80 -c -o $@ $<
.PRECIOUS: %.elf
-%.elf: %.o mbr.ld
- $(LD) $(LDFLAGS) -T mbr.ld -e _start -o $@ $<
+#%.elf: %.o mbr.ld
+%.elf: %.o $(ARCH)/mbr.ld
+ $(LD) $(LDFLAGS) -T $(ARCH)/mbr.ld -e _start -o $@ $<
%.bin: %.elf checksize.pl
$(OBJCOPY) -O binary $< $@
diff --git a/mbr/i386/mbr.ld b/mbr/i386/mbr.ld
new file mode 100644
index 00000000..d14ba802
--- /dev/null
+++ b/mbr/i386/mbr.ld
@@ -0,0 +1,73 @@
+/*
+ * Linker script for MBR
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x600;
+ .text :
+ {
+ *(.text*)
+ *(.rodata*)
+ } =0x90909090
+
+ . = ALIGN(4);
+ .data :
+ {
+ *(.data*)
+ }
+
+ . = ALIGN(128);
+ .bss :
+ {
+ *(.bss*)
+ }
+
+ . = 0x7c00;
+ .bootsec :
+ {
+ *(.bootsec)
+ }
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/mbr/x86_64/mbr.ld b/mbr/x86_64/mbr.ld
new file mode 100644
index 00000000..ae27d49a
--- /dev/null
+++ b/mbr/x86_64/mbr.ld
@@ -0,0 +1,72 @@
+/*
+ * Linker script for MBR
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x600;
+ .text :
+ {
+ *(.text*)
+ *(.rodata*)
+ } =0x90909090
+
+ . = ALIGN(4);
+ .data :
+ {
+ *(.data*)
+ }
+
+ . = ALIGN(128);
+ .bss :
+ {
+ *(.bss*)
+ }
+
+ . = 0x7c00;
+ .bootsec :
+ {
+ *(.bootsec)
+ }
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdisk/Makefile b/memdisk/Makefile
index b5cd52ce..36689979 100644
--- a/memdisk/Makefile
+++ b/memdisk/Makefile
@@ -84,7 +84,8 @@ memdisk_%.o: memdisk_%.bin
memdisk16.elf: $(OBJS16)
$(LD) -Ttext 0 -o $@ $^
-memdisk32.elf: memdisk.ld $(OBJS32)
+#memdisk32.elf: memdisk.ld $(OBJS32)
+memdisk32.elf: $(ARCH)/memdisk.ld $(OBJS32)
$(LD) -o $@ -T $^
%.bin: %.elf
diff --git a/memdisk/i386/memdisk.ld b/memdisk/i386/memdisk.ld
new file mode 100644
index 00000000..51c3e35c
--- /dev/null
+++ b/memdisk/i386/memdisk.ld
@@ -0,0 +1,140 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for MEMDISK
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x100000;
+ PROVIDE (__executable_start = .);
+
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(4);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { *(.preinit_array) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { *(.init_array) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { *(.fini_array) }
+ PROVIDE (__fini_array_end = .);
+ PROVIDE (__ctors_start = .);
+ .ctors :
+ {
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ PROVIDE (__ctors_end = .);
+ PROVIDE (__dtors_start = .);
+ .dtors :
+ {
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ PROVIDE (__dtors_end = .);
+
+ /* Adjust the address for the data segment. Avoid mixing code and
+ data within same 128-byte chunk. */
+ . = ALIGN(128);
+
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(16);
+ .bss :
+ {
+ __bss_start = .;
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(4);
+ __bss_end = .;
+ }
+ _end = .;
+ PROVIDE (end = .);
+
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdisk/memcpy.c b/memdisk/memcpy.c
new file mode 100644
index 00000000..5ce206d0
--- /dev/null
+++ b/memdisk/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb":"+c" (nl),
+ "+S"(p), "+D"(q)
+ :"r"(n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb":"+c"
+ (nq), "+S"(p), "+D"(q)
+ :"r"((uint32_t) (n & 7)));
+#else
+ while (n--) {
+ *q++ = *p++;
+ }
+#endif
+
+ return dst;
+}
diff --git a/memdisk/memdisk.h b/memdisk/memdisk.h
index b6b277a8..6da5aff9 100644
--- a/memdisk/memdisk.h
+++ b/memdisk/memdisk.h
@@ -24,7 +24,10 @@
/* We use the com32 interface for calling 16-bit code */
#include <com32.h>
+/* define it only for i386 */
+#if __SIZEOF_POINTER__ == 4
#define __cdecl __attribute__((cdecl,regparm(0)))
+#endif
void __cdecl intcall(uint8_t, com32sys_t *, com32sys_t *);
diff --git a/memdisk/memmove.c b/memdisk/memmove.c
new file mode 100644
index 00000000..a398cd8d
--- /dev/null
+++ b/memdisk/memmove.c
@@ -0,0 +1,36 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+ if (q < p) {
+ asm volatile("cld; rep; movsb"
+ : "+c" (n), "+S"(p), "+D"(q));
+ } else {
+ p += (n - 1);
+ q += (n - 1);
+ asm volatile("std; rep; movsb; cld"
+ : "+c" (n), "+S"(p), "+D"(q));
+ }
+#else
+ if (q < p) {
+ while (n--) {
+ *q++ = *p++;
+ }
+ } else {
+ p += n;
+ q += n;
+ while (n--) {
+ *--q = *--p;
+ }
+ }
+#endif
+
+ return dst;
+}
diff --git a/memdisk/memset.c b/memdisk/memset.c
new file mode 100644
index 00000000..aa00b5b1
--- /dev/null
+++ b/memdisk/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+ char *q = dst;
+
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile ("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+ : "+c" (nl), "+D" (q)
+ : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile ("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+ :"+c" (nq), "+D" (q)
+ : "a" ((unsigned char)c * 0x0101010101010101U),
+ "r" ((uint32_t) n & 7));
+#else
+ while (n--) {
+ *q++ = c;
+ }
+#endif
+
+ return dst;
+}
diff --git a/memdisk/setup.c b/memdisk/setup.c
index bc79e127..b6093b7a 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -671,7 +671,13 @@ static void relocate_rm_code(uint32_t newbase)
set_seg_base(gdt_base, 0x10, rm_args.rm_base);
set_seg_base(gdt_base, 0x18, rm_args.rm_base);
+#if __SIZEOF_POINTER__ == 4
asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base));
+#elif __SIZEOF_POINTER__ == 8
+ asm volatile ("lgdt %0"::"m" (*(char *)gdt_base));
+#else
+#error "unsupported architecture"
+#endif
*(uint32_t *) rm_args.rm_pmjmp += delta;
*(uint16_t *) rm_args.rm_rmjmp += delta >> 4;
diff --git a/memdisk/start32.S b/memdisk/start32.S
index 4fb05374..ecebe684 100644
--- a/memdisk/start32.S
+++ b/memdisk/start32.S
@@ -62,7 +62,13 @@ _start:
addl $8, %edi
loop 1b
+#if __SIZEOF_POINTER__ == 4
lidtl idt_ptr
+#elif __SIZEOF_POINTER__ == 8
+ lidt idt_ptr
+#else
+#error "unsupported architecture"
+#endif
/* Save arguments, switch stacks */
movl %esp, %eax /* Pointer to arguments */
diff --git a/memdisk/x86_64/memdisk.ld b/memdisk/x86_64/memdisk.ld
new file mode 100644
index 00000000..76abb0c0
--- /dev/null
+++ b/memdisk/x86_64/memdisk.ld
@@ -0,0 +1,140 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for MEMDISK
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x100000;
+ PROVIDE (__executable_start = .);
+
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(4);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { *(.preinit_array) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { *(.init_array) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { *(.fini_array) }
+ PROVIDE (__fini_array_end = .);
+ PROVIDE (__ctors_start = .);
+ .ctors :
+ {
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ PROVIDE (__ctors_end = .);
+ PROVIDE (__dtors_start = .);
+ .dtors :
+ {
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ PROVIDE (__dtors_end = .);
+
+ /* Adjust the address for the data segment. Avoid mixing code and
+ data within same 128-byte chunk. */
+ . = ALIGN(128);
+
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(16);
+ .bss :
+ {
+ __bss_start = .;
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(4);
+ __bss_end = .;
+ }
+ _end = .;
+ PROVIDE (end = .);
+
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdump/code16.h b/memdump/code16.h
index ca765651..ebf5ff49 100644
--- a/memdump/code16.h
+++ b/memdump/code16.h
@@ -1,6 +1,8 @@
/* Must be included first of all */
+#if __SIZEOF_POINTER__ == 4
#ifdef __ASSEMBLY__
.code16
#else
__asm__ (".code16gcc");
#endif
+#endif
diff --git a/mk/com32.mk b/mk/com32.mk
index bfba0e1b..89ede83e 100644
--- a/mk/com32.mk
+++ b/mk/com32.mk
@@ -17,13 +17,29 @@
include $(MAKEDIR)/syslinux.mk
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
GCCOPT := $(call gcc_ok,-std=gnu99,)
-GCCOPT += $(call gcc_ok,-m32,)
+ifeq ($(strip $(ARCH)),i386)
+ GCCOPT += $(call gcc_ok,-m32,)
+ GCCOPT += $(call gcc_ok,-march=i386)
+ GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+ GCCOPT += $(call gcc_ok,-incoming-stack-boundary=2,)
+endif
+ifeq ($(strip $(ARCH)),x86_64)
+ GCCOPT += $(call gcc_ok,-m64,)
+ GCCOPT += $(call gcc_ok,-march=x86-64)
+ #let the stack-boundary default to whatever it is on 64bit
+ #GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=8,)
+ #GCCOPT += $(call gcc_ok,-incoming-stack-boundary=8,)
+endif
GCCOPT += $(call gcc_ok,-fno-stack-protector,)
GCCOPT += $(call gcc_ok,-fwrapv,)
GCCOPT += $(call gcc_ok,-freg-struct-return,)
-GCCOPT += -mregparm=3 -DREGPARM=3 -march=i386 -Os
-GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+GCCOPT += -Os
+# Note -fPIE does not work with ld on x86_64, try -fPIC instead
+# Does BIOS build require -fPIE?
+GCCOPT += $(call gcc_ok,-fPIC)
GCCOPT += $(call gcc_ok,-fno-exceptions,)
GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
@@ -31,8 +47,6 @@ GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
-GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
-GCCOPT += $(call gcc_ok,-incoming-stack-boundary=2,)
com32 := $(topdir)/com32
RELOCS := $(com32)/tools/relocs
@@ -45,17 +59,19 @@ GPLLIB =
GPLINCLUDE =
endif
-CFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
+CFLAGS = $(GCCOPT) $(GCCWARN) \
-fomit-frame-pointer -D__COM32__ \
-nostdinc -iwithprefix include \
- -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
-SFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
+ -I$(com32)/libutil/include -I$(com32)/include \
+ -I$(com32)/include/sys $(GPLINCLUDE)
+SFLAGS = $(GCCOPT) $(GCCWARN) \
-fomit-frame-pointer -D__COM32__ \
-nostdinc -iwithprefix include \
- -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
+ -I$(com32)/libutil/include -I$(com32)/include \
+ -I$(com32)/include/sys $(GPLINCLUDE)
-COM32LD = $(com32)/lib/elf32.ld
-LDFLAGS = -m elf_i386 -shared --hash-style=gnu -T $(COM32LD)
+COM32LD = $(com32)/lib/$(ARCH)/elf.ld
+LDFLAGS = -m elf_$(ARCH) -shared --hash-style=gnu -T $(COM32LD)
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g \
diff --git a/mk/efi.mk b/mk/efi.mk
new file mode 100644
index 00000000..ede87d91
--- /dev/null
+++ b/mk/efi.mk
@@ -0,0 +1,60 @@
+include $(MAKEDIR)/syslinux.mk
+
+com32 = $(topdir)/com32
+core = $(topdir)/core
+
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
+# gnuefi sets up architecture specifics in ia32 or x86_64 sub directories
+# set up the LIBDIR and EFIINC for building for the appropriate architecture
+# For now, the following assumptions are made:
+# 1. gnu-efi lib for IA32 is installed in /usr/local/lib
+# and the include files in /usr/local/include/efi.
+# 2. gnu-efi lib for x86_64 is installed in /usr/lib
+# and the include files in /usr/include/efi.
+ifeq ($(ARCH),i386)
+ SARCHOPT = -march=i386
+ CARCHOPT = -m32 -march=i386
+ EFI_SUBARCH = ia32
+ LIBDIR = /usr/local/lib
+ EFIINC = /usr/local/include/efi
+endif
+ifeq ($(ARCH),x86_64)
+ SARCHOPT = -march=x86-64
+ CARCHOPT = -m64 -march=x86-64
+ EFI_SUBARCH = $(ARCH)
+ EFIINC = /usr/include/efi
+ LIBDIR=/usr/lib64
+endif
+#LIBDIR=/usr/lib
+FORMAT=efi-app-$(EFI_SUBARCH)
+
+CFLAGS = -I$(EFIINC) -I$(EFIINC)/$(EFI_SUBARCH) \
+ -DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \
+ -Wall -I$(com32)/include -I$(com32)/include/sys \
+ -I$(core)/include $(CARCHOPT) \
+ -I$(com32)/lib/ -std=gnu99 -DELF_DEBUG -DSYSLINUX_EFI
+
+# gnuefi sometimes installs these under a gnuefi/ directory, and sometimes not
+CRT0 := $(shell find $(LIBDIR) -name crt0-efi-$(EFI_SUBARCH).o 2>/dev/null | tail -n1)
+LDSCRIPT := $(shell find $(LIBDIR) -name elf_$(EFI_SUBARCH)_efi.lds 2>/dev/null | tail -n1)
+
+LDFLAGS = -T $(ARCH)/syslinux.ld -Bsymbolic -pie -nostdlib -znocombreloc \
+ -L$(LIBDIR) --hash-style=gnu -m elf_$(ARCH) $(CRT0) -E
+
+SFLAGS = $(GCCOPT) $(GCCWARN) $(SARCHOPT) \
+ -fomit-frame-pointer -D__COM32__ \
+ -nostdinc -iwithprefix include \
+ -I$(com32)/libutil/include -I$(com32)/include -I$(com32)/include/sys $(GPLINCLUDE)
+
+.PRECIOUS: %.o
+%.o: %.S
+ $(CC) $(SFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.o
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+#%.efi: %.so
+# $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+# -j .rela -j .reloc --target=$(FORMAT) $*.so $@
diff --git a/mk/elf.mk b/mk/elf.mk
index bc2948a3..bc83359c 100644
--- a/mk/elf.mk
+++ b/mk/elf.mk
@@ -16,20 +16,32 @@
include $(MAKEDIR)/syslinux.mk
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
GCCOPT := $(call gcc_ok,-std=gnu99,)
-GCCOPT += $(call gcc_ok,-m32,)
+ifeq ($(ARCH),i386)
+ GCCOPT += $(call gcc_ok,-m32,)
+ GCCOPT += $(call gcc_ok,-march=i386)
+ GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+endif
+ifeq ($(ARCH),x86_64)
+ GCCOPT += $(call gcc_ok,-m64,)
+ GCCOPT += $(call gcc_ok,-march=x86-64)
+ #let preferred-stack-boundary be default (=4)
+endif
+GCCOPT += -Os -fomit-frame-pointer
GCCOPT += $(call gcc_ok,-fno-stack-protector,)
GCCOPT += $(call gcc_ok,-fwrapv,)
GCCOPT += $(call gcc_ok,-freg-struct-return,)
-GCCOPT += -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3
GCCOPT += $(call gcc_ok,-fno-exceptions,)
GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
-GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+# Note -fPIE does not work with ld on x86_64, try -fPIC instead
+# Does BIOS build depend on -fPIE?
+GCCOPT += $(call gcc_ok,-fPIC)
GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
-GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
com32 = $(topdir)/com32
core = $(topdir)/core
@@ -42,13 +54,14 @@ GPLLIB =
GPLINCLUDE =
endif
-CFLAGS = $(GCCOPT) -W -Wall -march=i386 \
+CFLAGS = $(GCCOPT) -W -Wall \
-fomit-frame-pointer -D__COM32__ -DDYNAMIC_MODULE \
-nostdinc -iwithprefix include \
- -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE) \
- -I$(core)/include
-SFLAGS = $(GCCOPT) -D__COM32__ -march=i386
-LDFLAGS = -m elf_i386 -shared --hash-style=gnu -T $(com32)/lib/elf32.ld --as-needed
+ -I$(com32)/libutil/include -I$(com32)/include \
+ -I$(com32)/include/sys $(GPLINCLUDE) -I$(core)/include
+SFLAGS = $(GCCOPT) -D__COM32__
+LDFLAGS = -m elf_$(ARCH) -shared --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld --as-needed
+LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE
LNXSFLAGS = -g
diff --git a/mk/embedded.mk b/mk/embedded.mk
index e8f3ae30..16b2a52b 100644
--- a/mk/embedded.mk
+++ b/mk/embedded.mk
@@ -16,12 +16,30 @@
include $(MAKEDIR)/syslinux.mk
-GCCOPT := $(call gcc_ok,-m32,)
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
+# Initialize GCCOPT to null to begin with. Without this, make generates
+# recursive error for GCCOPT
+GCCOPT :=
+ifeq ($(ARCH),i386)
+ GCCOPT := $(call gcc_ok,-m32)
+ GCCOPT += $(call gcc_ok,-march=i386)
+ GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+ GCCOPT += $(call gcc_ok,-mincoming-stack-boundary=2,)
+endif
+ifeq ($(ARCH),x86_64)
+ GCCOPT := $(call gcc_ok,-m64)
+ GCCOPT += $(call gcc_ok,-march=x86-64)
+ #let preferred-stack-boundary and incoming-stack-boundary be default(=4)
+# Somewhere down the line ld barfs requiring -fPIC
+ #GCCOPT += $(call gcc_ok,-fPIC)
+endif
GCCOPT += $(call gcc_ok,-ffreestanding,)
GCCOPT += $(call gcc_ok,-fno-stack-protector,)
GCCOPT += $(call gcc_ok,-fwrapv,)
GCCOPT += $(call gcc_ok,-freg-struct-return,)
-GCCOPT += -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 \
+# FIXME: regparam for i386 and x86_64 could be different
+GCCOPT += -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 \
-msoft-float
GCCOPT += $(call gcc_ok,-fno-exceptions,)
GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
@@ -30,12 +48,11 @@ GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
-GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
-GCCOPT += $(call gcc_ok,-mincoming-stack-boundary=2,)
+
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
-LD += -m elf_i386
+LD += -m elf_$(ARCH)
# Note: use += for CFLAGS and SFLAGS in case something is set in MCONFIG.local
CFLAGS += $(GCCOPT) -g $(GCCWARN) -Wno-sign-compare $(OPTFLAGS) $(INCLUDES)
diff --git a/mk/lib.mk b/mk/lib.mk
index ea817e66..14bb327f 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -2,12 +2,25 @@
include $(MAKEDIR)/syslinux.mk
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
GCCOPT := $(call gcc_ok,-std=gnu99,)
-GCCOPT += $(call gcc_ok,-m32,)
+ifeq ($(ARCH),i386)
+ GCCOPT += $(call gcc_ok,-m32,)
+ GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+ MARCH = i386
+endif
+ifeq ($(ARCH),x86_64)
+ GCCOPT += $(call gcc_ok,-m64,)
+ #let preferred-stack-boundary be default(=4)
+ MARCH = x86-64
+endif
GCCOPT += $(call gcc_ok,-fno-stack-protector,)
GCCOPT += $(call gcc_ok,-fwrapv,)
GCCOPT += $(call gcc_ok,-freg-struct-return,)
-GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+# Note -fPIE does not work with ld on x86_64, try -fPIC instead
+# Does BIOS build require -fPIE?
+GCCOPT += $(call gcc_ok,-fPIC)
GCCOPT += $(call gcc_ok,-fno-exceptions,)
GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
@@ -15,7 +28,6 @@ GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
-GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
INCLUDE = -I.
STRIP = strip --strip-all -R .comment -R .note
@@ -31,15 +43,170 @@ LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \
# fallback anyway, just use that on old machines...
# LIBFLAGS += -DPNG_NO_FLOATING_POINT_SUPPORTED
-REQFLAGS = $(GCCOPT) -g -mregparm=3 -DREGPARM=3 -D__COM32__ \
+REQFLAGS = $(GCCOPT) -g -D__COM32__ \
-nostdinc -iwithprefix include -I. -I./sys -I../include \
- -I../../core/include
-OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \
+ -I../include/sys -I../../core/include -I$(com32)/lib/ \
+ -I$(com32)/lib/sys/module
+OPTFLAGS = -Os -march=$(MARCH) -falign-functions=0 -falign-jumps=0 \
-falign-labels=0 -ffast-math -fomit-frame-pointer
WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
+ifdef EFI_BUILD
+#Add console read fixes to rawcon_read.c
+LIBFLAGS += -DSYSLINUX_EFI -DEFI_FUNCTION_WRAPPER
+ifeq ($(ARCH),i386)
+ EFIINC = -I/usr/local/include/efi -I/usr/local/include/efi/ia32
+endif
+ifeq ($(ARCH),x86_64)
+ EFIINC = -I/usr/include/efi -I/usr/include/efi/x86_64
+endif
+REQFLAGS += $(EFIINC)
+endif
CFLAGS = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
-LDFLAGS = -m elf_i386 --hash-style=gnu -T $(com32)/lib/elf32.ld
+
+LIBOTHER_OBJS = \
+ atoi.o atol.o atoll.o calloc.o creat.o \
+ fgets.o fprintf.o fputc.o \
+ putchar.o \
+ getopt.o getopt_long.o \
+ lrand48.o stack.o memccpy.o memchr.o \
+ mempcpy.o memmem.o memmove.o memswap.o \
+ perror.o qsort.o seed48.o \
+ srand48.o sscanf.o strcasecmp.o strcat.o \
+ strerror.o \
+ strnlen.o \
+ strncat.o strndup.o \
+ stpncpy.o \
+ strntoimax.o strntoumax.o strsep.o strspn.o strstr.o \
+ strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o \
+ strtoumax.o vprintf.o vsprintf.o \
+ asprintf.o vasprintf.o \
+ vsscanf.o \
+ skipspace.o \
+ chrreplace.o \
+ bufprintf.o \
+ inet.o dhcppack.o dhcpunpack.o \
+ strreplace.o \
+ lstrdup.o \
+ \
+ suffix_number.o \
+ \
+ getcwd.o fdopendir.o \
+ \
+ sys/line_input.o \
+ sys/colortable.o sys/screensize.o \
+ \
+ sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
+ sys/rawcon_write.o \
+ sys/null_read.o sys/null_write.o sys/serial_write.o \
+ \
+ sys/xserial_write.o \
+ \
+ sys/ansi.o \
+ \
+ sys/ansicon_write.o sys/ansiserial_write.o \
+ \
+ pci/cfgtype.o pci/scan.o pci/bios.o \
+ pci/readb.o pci/readw.o pci/readl.o \
+ pci/writeb.o pci/writew.o pci/writel.o \
+ \
+ sys/x86_init_fpu.o math/pow.o math/strtod.o \
+ syslinux/disk.o \
+ \
+ syslinux/setup_data.o
+
+## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE
+LIBENTRY_OBJS = \
+ sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o \
+ sys/argv.o sys/sleep.o \
+ sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
+ sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \
+ sys/openmem.o \
+ sys/isatty.o sys/fstat.o \
+ \
+ dprintf.o vdprintf.o \
+ \
+ syslinux/idle.o \
+ \
+ exit.o
+
+LIBGCC_OBJS = \
+ libgcc/__ashldi3.o libgcc/__udivdi3.o \
+ libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
+ libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
+ libgcc/__divdi3.o libgcc/__moddi3.o
+
+LIBCONSOLE_OBJS = \
+ \
+ sys/openconsole.o sys/line_input.o \
+ sys/colortable.o sys/screensize.o \
+ \
+ sys/stdcon_read.o sys/rawcon_read.o \
+ sys/rawcon_write.o \
+ sys/null_write.o sys/serial_write.o \
+ \
+ sys/xserial_write.o \
+ \
+ sys/ansi.o \
+ \
+ sys/ansicon_write.o sys/ansiserial_write.o \
+ \
+ syslinux/serial.o
+
+LIBLOAD_OBJS = \
+ syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \
+ syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \
+ syslinux/shuffle_rm.o syslinux/zonelist.o \
+ syslinux/dump_mmap.o syslinux/dump_movelist.o \
+ \
+ syslinux/run_default.o syslinux/run_command.o \
+ syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \
+ \
+ syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \
+ \
+ syslinux/load_linux.o syslinux/initramfs.o \
+ syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \
+ syslinux/initramfs_archive.o
+
+LIBMODULE_OBJS = \
+ sys/module/common.o sys/module/$(ARCH)/elf_module.o \
+ sys/module/$(ARCH)/shallow_module.o sys/module/elfutils.o \
+ sys/module/exec.o
+
+# ZIP library object files
+LIBZLIB_OBJS = \
+ zlib/adler32.o zlib/compress.o zlib/crc32.o \
+ zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \
+ zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o \
+ sys/zfile.o sys/zfopen.o
+
+MINLIBOBJS = \
+ syslinux/ipappend.o \
+ syslinux/dsinfo.o \
+ $(LIBOTHER_OBJS) \
+ $(LIBGCC_OBJS) \
+ $(LIBCONSOLE_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(LIBZLIB_OBJS)
+# $(LIBVESA_OBJS)
+
+CORELIBOBJS = \
+ memcpy.o memset.o memcmp.o printf.o strncmp.o vfprintf.o \
+ strlen.o vsnprintf.o snprintf.o stpcpy.o strcmp.o strdup.o \
+ strcpy.o strncpy.o setjmp.o fopen.o fread.o fread2.o puts.o \
+ sprintf.o strlcat.o strchr.o strlcpy.o strncasecmp.o ctypes.o \
+ fputs.o fwrite2.o fwrite.o fgetc.o fclose.o errno.o lmalloc.o \
+ sys/err_read.o sys/err_write.o sys/null_read.o \
+ sys/stdcon_write.o sys/openconsole.o \
+ syslinux/memscan.o strrchr.o \
+ libgcc/__ashldi3.o libgcc/__udivdi3.o \
+ libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
+ libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
+ libgcc/__divdi3.o libgcc/__moddi3.o \
+ $(LIBENTRY_OBJS) \
+ $(LIBMODULE_OBJS)
+
+LDFLAGS = -m elf_$(ARCH) --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld
.SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss
diff --git a/mk/syslinux.mk b/mk/syslinux.mk
index 4cf34e36..cab80102 100644
--- a/mk/syslinux.mk
+++ b/mk/syslinux.mk
@@ -66,6 +66,12 @@ WGET = wget
com32 = $(topdir)/com32
+# Architecture definition
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/)
+# on x86_64, ARCH has trailing whitespace
+# strip white spaces in ARCH
+ARCH ?= $(strip $(SUBARCH))
+
# Common warnings we want for all gcc-generated code
GCCWARN := -W -Wall -Wstrict-prototypes
# Extremely useful variant for debugging...