From: srs5694 Date: Sun, 25 Mar 2012 23:17:42 +0000 (-0400) Subject: Added remaining main project files X-Git-Url: https://code.delx.au/refind/commitdiff_plain/6ddfd09a30d788c784840b1f6dfc3d9281b33726?ds=sidebyside Added remaining main project files --- diff --git a/Make.common b/Make.common new file mode 100644 index 0000000..f8eff66 --- /dev/null +++ b/Make.common @@ -0,0 +1,112 @@ +# +# Make.common +# Common make rules for building with gnu-efi +# + +EFIINC = /usr/include/efi +GNUEFILIB = /usr/lib +EFILIB = /usr/lib +EFICRT0 = /usr/lib + +HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ARCH := $(HOSTARCH) +OS = $(shell uname -s) +CPPFLAGS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -DCONFIG_$(ARCH) + +OPTIMFLAGS = -O2 -fno-strict-aliasing +DEBUGFLAGS = -Wall +CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS) +ASFLAGS = $(ARCH3264) +LDFLAGS = -nostdlib -znocombreloc + +prefix = /usr/bin/ +CC = $(prefix)gcc +AS = $(prefix)as +LD = $(prefix)ld +AR = $(prefix)ar +RANLIB = $(prefix)ranlib +OBJCOPY = $(prefix)objcopy + +ifeq ($(ARCH),ia64) + # EFI specs allows only lower floating point partition to be used + CFLAGS += -frename-registers -mfixed-range=f32-f127 +endif + +ifeq ($(ARCH),x86_64) + CFLAGS += -DEFI_FUNCTION_WRAPPER + CPPFLAGS += -DEFIX64 + + ifeq ($(HOSTARCH),ia32) + ARCH3264 = -m64 + + GNUEFILIB := $(GNUEFILIB)64 + EFILIB := $(EFILIB)64 + EFICRT0 := $(EFICRT0)64 + endif +endif + +ifeq ($(ARCH),ia32) + CPPFLAGS += -DEFI32 + + ifeq ($(HOSTARCH),x86_64) + ARCH3264 = -m32 + + GNUEFILIB := $(GNUEFILIB)32 + EFILIB := $(EFILIB)32 + EFICRT0 := $(EFICRT0)32 + endif +endif + + +CRTOBJS = $(EFICRT0)/crt0-efi-$(ARCH).o + +ifneq (,$(findstring FreeBSD,$(OS))) + ifeq ($(ARCH),x86_64) + LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_fbsd_efi.lds + else + LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds + endif +else + LDSCRIPT = $(EFICRT0)/elf_$(ARCH)_efi.lds +endif + +LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFILIB) -L$(GNUEFILIB) $(CRTOBJS) +LIBS = -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name) +FORMAT = efi-app-$(ARCH) + + +# general rules + +%.o: %.c + $(CC) $(LOCAL_CPPFLAGS) $(CPPFLAGS) $(LOCAL_CFLAGS) $(CFLAGS) -c $< -o $@ + +# rules for EFI applications + +ifneq (,$(filter %.efi,$(TARGET))) + +SHLIB_TARGET = $(subst .efi,.so,$(TARGET)) + +$(SHLIB_TARGET): $(OBJS) + $(LD) $(LOCAL_LDFLAGS) $(LDFLAGS) $(OBJS) -o $@ $(LOCAL_LIBS) $(LIBS) + +$(TARGET): $(SHLIB_TARGET) + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ + -j .rela -j .reloc --target=$(FORMAT) $< $@ + +endif + +# rules for libraries + +ifneq (,$(filter %.a,$(TARGET))) + +$(TARGET): $(OBJS) + $(AR) cq $@ $(OBJS) + +endif + +# utility rules + +clean: + rm -f $(TARGET) *~ *.so $(OBJS) + +# EOF diff --git a/include/egemb_arrow_left.h b/include/egemb_arrow_left.h new file mode 100644 index 0000000..ba09d8d --- /dev/null +++ b/include/egemb_arrow_left.h @@ -0,0 +1,204 @@ +static const UINT8 egemb_arrow_left_data[2407] = { + 0xff, 0xff, 0xdc, 0xff, 0x02, 0x00, 0x13, 0x21, 0xa8, 0xff, 0x80, 0x00, + 0x02, 0x5e, 0x74, 0x00, 0xa6, 0xff, 0x80, 0x00, 0x03, 0x43, 0xb2, 0x30, + 0x00, 0xa5, 0xff, 0x80, 0x00, 0x04, 0x62, 0x9f, 0x8a, 0x00, 0x00, 0xa4, + 0xff, 0x08, 0x00, 0x00, 0x09, 0x7a, 0x96, 0x91, 0x56, 0x00, 0x00, 0xa2, + 0xff, 0x80, 0x00, 0x07, 0x1d, 0x85, 0x8c, 0x8b, 0x89, 0x53, 0x00, 0x00, + 0xa1, 0xff, 0x80, 0x00, 0x08, 0x34, 0x87, 0x85, 0x84, 0x82, 0x81, 0x50, + 0x00, 0x00, 0xa0, 0xff, 0x80, 0x00, 0x09, 0x4c, 0x84, 0x7f, 0x7d, 0x7c, + 0x7a, 0x79, 0x4d, 0x00, 0x00, 0x9f, 0xff, 0x0d, 0x00, 0x00, 0x07, 0x60, + 0x7c, 0x79, 0x76, 0x75, 0x73, 0x72, 0x70, 0x49, 0x00, 0x00, 0x9d, 0xff, + 0x80, 0x00, 0x0c, 0x16, 0x69, 0x73, 0x71, 0x70, 0x6e, 0x6d, 0x6b, 0x6a, + 0x68, 0x46, 0x00, 0x00, 0x9c, 0xff, 0x80, 0x00, 0x0d, 0x26, 0x6c, 0x6d, + 0x6a, 0x69, 0x67, 0x66, 0x64, 0x63, 0x61, 0x60, 0x42, 0x00, 0x00, 0x9b, + 0xff, 0x80, 0x00, 0x0e, 0x38, 0x69, 0x66, 0x64, 0x62, 0x61, 0x5f, 0x5e, + 0x5c, 0x5b, 0x59, 0x58, 0x3f, 0x00, 0x00, 0x9a, 0xff, 0x12, 0x00, 0x00, + 0x05, 0x47, 0x62, 0x5e, 0x5d, 0x5b, 0x5a, 0x58, 0x57, 0x55, 0x54, 0x52, + 0x51, 0x4f, 0x3d, 0x00, 0x00, 0x98, 0xff, 0x80, 0x00, 0x11, 0x0e, 0x4d, + 0x5a, 0x58, 0x56, 0x55, 0x53, 0x52, 0x50, 0x4f, 0x4d, 0x4c, 0x4a, 0x49, + 0x47, 0x3a, 0x00, 0x00, 0x97, 0xff, 0x80, 0x00, 0x12, 0x1a, 0x50, 0x53, + 0x51, 0x4f, 0x4e, 0x4c, 0x4b, 0x49, 0x48, 0x46, 0x45, 0x43, 0x42, 0x40, + 0x3f, 0x38, 0x00, 0x00, 0x96, 0xff, 0x80, 0x00, 0x13, 0x25, 0x4d, 0x4c, + 0x4a, 0x49, 0x47, 0x46, 0x44, 0x43, 0x41, 0x40, 0x3e, 0x3d, 0x3b, 0x3a, + 0x38, 0x37, 0x36, 0x00, 0x00, 0x95, 0xff, 0x17, 0x00, 0x00, 0x05, 0x2f, + 0x47, 0x45, 0x43, 0x42, 0x40, 0x3f, 0x3d, 0x3c, 0x3a, 0x39, 0x37, 0x36, + 0x34, 0x33, 0x31, 0x30, 0x2e, 0x34, 0x00, 0x00, 0x93, 0xff, 0x80, 0x00, + 0x16, 0x0a, 0x39, 0x40, 0x3f, 0x3d, 0x3c, 0x3a, 0x38, 0x37, 0x35, 0x34, + 0x32, 0x31, 0x2f, 0x2e, 0x2c, 0x2b, 0x29, 0x27, 0x25, 0x32, 0x00, 0x00, + 0x92, 0xff, 0x1a, 0x25, 0x08, 0x05, 0x14, 0x39, 0x3a, 0x38, 0x37, 0x34, + 0x33, 0x31, 0x30, 0x2e, 0x2d, 0x2b, 0x2a, 0x28, 0x27, 0x25, 0x24, 0x22, + 0x20, 0x1f, 0x1d, 0x30, 0x00, 0x00, 0x92, 0xff, 0x10, 0x1d, 0x37, 0x48, + 0x39, 0x32, 0x31, 0x31, 0x30, 0x2e, 0x2d, 0x2b, 0x2b, 0x2a, 0x2d, 0x2e, + 0x32, 0x31, 0x84, 0x30, 0x02, 0x33, 0x00, 0x00, 0x92, 0xff, 0x0f, 0x3a, + 0x5c, 0x5a, 0x0f, 0x00, 0x00, 0x02, 0x04, 0x05, 0x08, 0x0b, 0x0e, 0x0c, + 0x09, 0x05, 0x01, 0x85, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x92, 0xff, 0x04, + 0x94, 0x33, 0x17, 0x0b, 0x05, 0x90, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x93, + 0xff, 0x04, 0xab, 0x02, 0x00, 0x06, 0x0a, 0x8f, 0x00, 0x02, 0x0d, 0x00, + 0x00, 0x95, 0xff, 0x03, 0x00, 0x00, 0x05, 0x10, 0x8e, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x96, 0xff, 0x04, 0x00, 0x00, 0x01, 0x00, 0x05, 0x8c, 0x00, + 0x02, 0x11, 0x00, 0x00, 0x97, 0xff, 0x80, 0x00, 0x01, 0x0f, 0x09, 0x8b, + 0x00, 0x02, 0x12, 0x00, 0x00, 0x98, 0xff, 0x80, 0x00, 0x01, 0x0b, 0x10, + 0x8a, 0x00, 0x02, 0x14, 0x00, 0x00, 0x9a, 0xff, 0x03, 0x00, 0x00, 0x07, + 0x18, 0x89, 0x00, 0x02, 0x16, 0x00, 0x00, 0x9b, 0xff, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x07, 0x87, 0x00, 0x02, 0x17, 0x00, 0x00, 0x9c, 0xff, 0x80, + 0x00, 0x01, 0x15, 0x0d, 0x86, 0x00, 0x02, 0x19, 0x00, 0x00, 0x9d, 0xff, + 0x80, 0x00, 0x01, 0x0e, 0x17, 0x85, 0x00, 0x02, 0x1b, 0x00, 0x00, 0x9f, + 0xff, 0x04, 0x00, 0x00, 0x09, 0x20, 0x01, 0x83, 0x00, 0x02, 0x1d, 0x00, + 0x00, 0xa0, 0xff, 0x04, 0x00, 0x00, 0x01, 0x22, 0x09, 0x82, 0x00, 0x02, + 0x1e, 0x00, 0x00, 0xa1, 0xff, 0x80, 0x00, 0x01, 0x1b, 0x12, 0x81, 0x00, + 0x02, 0x20, 0x00, 0x00, 0xa2, 0xff, 0x80, 0x00, 0x01, 0x13, 0x1d, 0x80, + 0x00, 0x02, 0x22, 0x00, 0x00, 0xa4, 0xff, 0x08, 0x00, 0x00, 0x0b, 0x29, + 0x01, 0x00, 0x24, 0x00, 0x00, 0xa5, 0xff, 0x07, 0x00, 0x00, 0x02, 0x2b, + 0x0b, 0x3c, 0x00, 0x00, 0xa6, 0xff, 0x80, 0x00, 0x03, 0x23, 0x66, 0x0b, + 0x00, 0xa7, 0xff, 0x80, 0x00, 0x02, 0x39, 0x24, 0x00, 0xa9, 0xff, 0x02, + 0x00, 0x11, 0x0b, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xdc, 0xff, 0x02, + 0x4d, 0x59, 0x64, 0xa8, 0xff, 0x05, 0x80, 0x4b, 0x4d, 0x8f, 0x9e, 0x49, + 0xa6, 0xff, 0x06, 0x4f, 0x4c, 0x4d, 0x7d, 0xd2, 0x6f, 0x47, 0xa5, 0xff, + 0x07, 0x49, 0x4d, 0x4d, 0x96, 0xd6, 0xb8, 0x4d, 0x4e, 0xa4, 0xff, 0x08, + 0x4d, 0x4d, 0x53, 0xac, 0xd1, 0xce, 0x91, 0x4d, 0x4e, 0xa2, 0xff, 0x0a, + 0x80, 0x4b, 0x4d, 0x62, 0xb9, 0xca, 0xc9, 0xc8, 0x91, 0x4d, 0x4e, 0xa1, + 0xff, 0x0b, 0x4f, 0x4c, 0x4d, 0x74, 0xc0, 0xc5, 0xc4, 0xc3, 0xc1, 0x8f, + 0x4d, 0x4e, 0xa0, 0xff, 0x0c, 0x49, 0x4d, 0x4d, 0x8a, 0xc1, 0xc1, 0xbf, + 0xbe, 0xbd, 0xbc, 0x8f, 0x50, 0x4e, 0x9f, 0xff, 0x0d, 0x4d, 0x4d, 0x53, + 0x9d, 0xbe, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, 0xb7, 0x8e, 0x54, 0x4e, 0x9d, + 0xff, 0x05, 0x80, 0x4b, 0x4d, 0x5e, 0xa8, 0xb8, 0x80, 0xb6, 0x06, 0xb5, + 0xb4, 0xb3, 0xb3, 0x8f, 0x59, 0x4e, 0x9c, 0xff, 0x05, 0x4f, 0x4c, 0x4d, + 0x6d, 0xad, 0xb3, 0x81, 0xb2, 0x06, 0xb1, 0xb0, 0xb0, 0xaf, 0x90, 0x5e, + 0x4e, 0x9b, 0xff, 0x03, 0x4f, 0x4f, 0x51, 0x7f, 0x82, 0xad, 0x00, 0xae, + 0x80, 0xad, 0x04, 0xac, 0xac, 0x91, 0x62, 0x4e, 0x9a, 0xff, 0x0a, 0x50, + 0x53, 0x58, 0x8d, 0xa8, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0x81, 0xaa, + 0x03, 0xa9, 0x94, 0x67, 0x4e, 0x98, 0xff, 0x0c, 0x80, 0x51, 0x55, 0x62, + 0x93, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0x81, 0xa8, 0x03, + 0xa7, 0x96, 0x6c, 0x4e, 0x97, 0xff, 0x15, 0x4f, 0x56, 0x59, 0x6c, 0x95, + 0x9b, 0x9c, 0x9e, 0x9f, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, + 0xa6, 0xa6, 0x98, 0x6f, 0x4e, 0x96, 0xff, 0x0f, 0x4d, 0x58, 0x5b, 0x71, + 0x93, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa1, 0xa2, 0xa3, 0xa4, + 0x81, 0xa5, 0x02, 0x99, 0x72, 0x4e, 0x95, 0xff, 0x17, 0x55, 0x5a, 0x61, + 0x77, 0x8b, 0x8d, 0x8e, 0x91, 0x94, 0x96, 0x99, 0x9b, 0x9c, 0x9f, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa4, 0x9c, 0x75, 0x4e, 0x93, 0xff, 0x13, + 0x80, 0x56, 0x5f, 0x64, 0x7b, 0x82, 0x85, 0x88, 0x8b, 0x8d, 0x8f, 0x93, + 0x96, 0x98, 0x9b, 0x9d, 0x9f, 0xa1, 0xa3, 0xa4, 0x80, 0xa5, 0x02, 0x9f, + 0x77, 0x4e, 0x92, 0xff, 0x1a, 0x6d, 0x60, 0x63, 0x68, 0x77, 0x79, 0x7c, + 0x7f, 0x82, 0x85, 0x88, 0x8c, 0x8f, 0x92, 0x96, 0x99, 0x9c, 0x9e, 0xa0, + 0xa2, 0xa4, 0xa4, 0xa5, 0xa5, 0xa1, 0x7a, 0x4e, 0x92, 0xff, 0x1a, 0x6a, + 0x85, 0x86, 0x6f, 0x6e, 0x73, 0x78, 0x7a, 0x7f, 0x82, 0x86, 0x89, 0x8e, + 0x94, 0x99, 0x9e, 0xa2, 0xa5, 0xa8, 0xab, 0xac, 0xaf, 0xaf, 0xb1, 0xa5, + 0x7d, 0x4e, 0x92, 0xff, 0x1a, 0x80, 0x9d, 0x90, 0x43, 0x3d, 0x44, 0x4d, + 0x54, 0x5d, 0x65, 0x6e, 0x76, 0x7a, 0x7e, 0x82, 0x85, 0x8b, 0x90, 0x95, + 0x99, 0x9d, 0xa0, 0xa2, 0xa3, 0x97, 0x7f, 0x4e, 0x92, 0xff, 0x1a, 0xb7, + 0x82, 0x76, 0x68, 0x48, 0x46, 0x4d, 0x54, 0x5b, 0x62, 0x69, 0x70, 0x77, + 0x7d, 0x83, 0x89, 0x8f, 0x95, 0x9a, 0x9f, 0xa3, 0xa6, 0xa9, 0xaa, 0x9c, + 0x80, 0x4e, 0x93, 0xff, 0x19, 0xd5, 0x61, 0x6b, 0x6d, 0x5b, 0x4f, 0x56, + 0x5d, 0x65, 0x6c, 0x72, 0x79, 0x80, 0x87, 0x8d, 0x93, 0x99, 0x9f, 0xa4, + 0xa9, 0xac, 0xaf, 0xb1, 0xa1, 0x84, 0x4e, 0x95, 0xff, 0x17, 0x61, 0x6e, + 0x72, 0x6a, 0x58, 0x5f, 0x66, 0x6e, 0x75, 0x7c, 0x83, 0x8a, 0x90, 0x97, + 0x9d, 0xa3, 0xa9, 0xae, 0xb2, 0xb6, 0xb8, 0xa5, 0x84, 0x4e, 0x96, 0xff, + 0x16, 0x5c, 0x6e, 0x74, 0x6a, 0x65, 0x68, 0x6f, 0x76, 0x7e, 0x85, 0x8c, + 0x93, 0x9a, 0xa1, 0xa7, 0xad, 0xb3, 0xb8, 0xbc, 0xbf, 0xaa, 0x86, 0x4e, + 0x97, 0xff, 0x15, 0x59, 0x6d, 0x76, 0x7d, 0x72, 0x70, 0x78, 0x7f, 0x86, + 0x8e, 0x95, 0x9c, 0xa3, 0xaa, 0xb1, 0xb7, 0xbd, 0xc2, 0xc6, 0xaf, 0x87, + 0x4e, 0x98, 0xff, 0x14, 0x80, 0x6c, 0x78, 0x7f, 0x7d, 0x78, 0x80, 0x87, + 0x8f, 0x96, 0x9e, 0xa5, 0xac, 0xb3, 0xbb, 0xc1, 0xc7, 0xcc, 0xb3, 0x8a, + 0x4e, 0x9a, 0xff, 0x12, 0x68, 0x79, 0x7f, 0x89, 0x80, 0x87, 0x8f, 0x96, + 0x9e, 0xa6, 0xad, 0xb5, 0xbc, 0xc4, 0xcb, 0xd1, 0xb7, 0x89, 0x4e, 0x9b, + 0xff, 0x11, 0x63, 0x7a, 0x7e, 0x8f, 0x8b, 0x8e, 0x96, 0x9e, 0xa5, 0xad, + 0xb5, 0xbc, 0xc4, 0xcc, 0xd3, 0xbb, 0x8a, 0x4e, 0x9c, 0xff, 0x10, 0x59, + 0x78, 0x7f, 0x8e, 0x93, 0x94, 0x9c, 0xa4, 0xab, 0xb3, 0xba, 0xc2, 0xc9, + 0xd0, 0xb8, 0x8a, 0x4e, 0x9d, 0xff, 0x0f, 0x80, 0x74, 0x80, 0x8c, 0x9a, + 0x99, 0xa1, 0xa8, 0xaf, 0xb6, 0xbd, 0xc3, 0xc8, 0xb5, 0x8b, 0x4e, 0x9f, + 0xff, 0x0d, 0x72, 0x82, 0x89, 0xa0, 0x9d, 0xa4, 0xab, 0xb1, 0xb7, 0xbc, + 0xc0, 0xb2, 0x8c, 0x4e, 0xa0, 0xff, 0x0c, 0x6b, 0x82, 0x86, 0x9f, 0xa2, + 0xa5, 0xab, 0xb0, 0xb4, 0xb7, 0xae, 0x8c, 0x4e, 0xa1, 0xff, 0x0b, 0x59, + 0x81, 0x85, 0x98, 0xa4, 0xa4, 0xa8, 0xac, 0xae, 0xac, 0x8b, 0x4e, 0xa2, + 0xff, 0x0a, 0x80, 0x7e, 0x87, 0x92, 0xa5, 0xa0, 0xa3, 0xa5, 0xa8, 0x8b, + 0x4e, 0xa4, 0xff, 0x08, 0x76, 0x87, 0x8d, 0xa5, 0x9a, 0x9c, 0xa5, 0x8b, + 0x4e, 0xa5, 0xff, 0x07, 0x70, 0x88, 0x88, 0xa3, 0x98, 0xab, 0x8a, 0x4e, + 0xa6, 0xff, 0x06, 0x63, 0x89, 0x86, 0x9b, 0xbd, 0x8e, 0x47, 0xa7, 0xff, + 0x05, 0x80, 0x84, 0x87, 0xa4, 0x9e, 0x66, 0xa9, 0xff, 0x02, 0x79, 0x8c, + 0x80, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xdc, 0xff, 0x02, 0x00, 0x13, + 0x21, 0xa8, 0xff, 0x80, 0x00, 0x02, 0x5e, 0x74, 0x00, 0xa6, 0xff, 0x80, + 0x00, 0x03, 0x43, 0xb2, 0x30, 0x00, 0xa5, 0xff, 0x80, 0x00, 0x04, 0x62, + 0x9f, 0x8a, 0x00, 0x00, 0xa4, 0xff, 0x08, 0x00, 0x00, 0x09, 0x7a, 0x96, + 0x91, 0x56, 0x00, 0x00, 0xa2, 0xff, 0x80, 0x00, 0x07, 0x1d, 0x85, 0x8c, + 0x8b, 0x89, 0x53, 0x00, 0x00, 0xa1, 0xff, 0x80, 0x00, 0x08, 0x34, 0x87, + 0x85, 0x84, 0x82, 0x81, 0x50, 0x00, 0x00, 0xa0, 0xff, 0x80, 0x00, 0x09, + 0x4c, 0x84, 0x7f, 0x7d, 0x7c, 0x7a, 0x79, 0x4d, 0x00, 0x00, 0x9f, 0xff, + 0x0d, 0x00, 0x00, 0x07, 0x60, 0x7c, 0x79, 0x76, 0x75, 0x73, 0x72, 0x70, + 0x49, 0x00, 0x00, 0x9d, 0xff, 0x80, 0x00, 0x0c, 0x16, 0x69, 0x73, 0x71, + 0x70, 0x6e, 0x6d, 0x6b, 0x6a, 0x68, 0x46, 0x00, 0x00, 0x9c, 0xff, 0x80, + 0x00, 0x0d, 0x26, 0x6c, 0x6d, 0x6a, 0x69, 0x67, 0x66, 0x64, 0x63, 0x61, + 0x60, 0x42, 0x00, 0x00, 0x9b, 0xff, 0x80, 0x00, 0x0e, 0x38, 0x69, 0x66, + 0x64, 0x62, 0x61, 0x5f, 0x5e, 0x5c, 0x5b, 0x59, 0x58, 0x3f, 0x00, 0x00, + 0x9a, 0xff, 0x12, 0x00, 0x00, 0x05, 0x47, 0x62, 0x5e, 0x5d, 0x5b, 0x5a, + 0x58, 0x57, 0x55, 0x54, 0x52, 0x51, 0x4f, 0x3d, 0x00, 0x00, 0x98, 0xff, + 0x80, 0x00, 0x11, 0x0e, 0x4d, 0x5a, 0x58, 0x56, 0x55, 0x53, 0x52, 0x50, + 0x4f, 0x4d, 0x4c, 0x4a, 0x49, 0x47, 0x3a, 0x00, 0x00, 0x97, 0xff, 0x15, + 0x00, 0x00, 0x01, 0x1b, 0x50, 0x53, 0x51, 0x4f, 0x4e, 0x4c, 0x4b, 0x49, + 0x48, 0x46, 0x45, 0x43, 0x42, 0x40, 0x3f, 0x38, 0x01, 0x00, 0x96, 0xff, + 0x16, 0x00, 0x01, 0x01, 0x26, 0x4d, 0x4c, 0x4a, 0x49, 0x47, 0x46, 0x44, + 0x43, 0x41, 0x40, 0x3e, 0x3d, 0x3b, 0x3a, 0x38, 0x37, 0x36, 0x01, 0x00, + 0x95, 0xff, 0x17, 0x00, 0x01, 0x06, 0x2f, 0x47, 0x45, 0x43, 0x42, 0x40, + 0x3f, 0x3d, 0x3c, 0x3a, 0x39, 0x37, 0x36, 0x34, 0x33, 0x31, 0x30, 0x2e, + 0x34, 0x01, 0x00, 0x93, 0xff, 0x19, 0x00, 0x02, 0x01, 0x0b, 0x39, 0x40, + 0x3f, 0x3d, 0x3c, 0x3a, 0x38, 0x37, 0x35, 0x34, 0x32, 0x31, 0x2f, 0x2e, + 0x2c, 0x2b, 0x29, 0x27, 0x25, 0x32, 0x01, 0x00, 0x92, 0xff, 0x1a, 0x25, + 0x09, 0x06, 0x15, 0x39, 0x3a, 0x38, 0x37, 0x34, 0x33, 0x31, 0x30, 0x2e, + 0x2d, 0x2b, 0x2a, 0x28, 0x27, 0x25, 0x24, 0x22, 0x20, 0x1f, 0x1d, 0x30, + 0x01, 0x00, 0x92, 0xff, 0x10, 0x1f, 0x39, 0x49, 0x39, 0x32, 0x31, 0x31, + 0x30, 0x2e, 0x2d, 0x2b, 0x2b, 0x2a, 0x2d, 0x2e, 0x32, 0x31, 0x84, 0x30, + 0x02, 0x34, 0x02, 0x00, 0x92, 0xff, 0x0f, 0x3c, 0x5d, 0x5b, 0x0f, 0x00, + 0x00, 0x02, 0x04, 0x05, 0x08, 0x0b, 0x0e, 0x0c, 0x09, 0x05, 0x01, 0x85, + 0x00, 0x02, 0x0b, 0x02, 0x00, 0x92, 0xff, 0x04, 0x94, 0x34, 0x19, 0x0d, + 0x05, 0x90, 0x00, 0x02, 0x0d, 0x02, 0x00, 0x93, 0xff, 0x04, 0xab, 0x04, + 0x02, 0x08, 0x0a, 0x8f, 0x00, 0x02, 0x0e, 0x02, 0x00, 0x95, 0xff, 0x03, + 0x03, 0x02, 0x08, 0x11, 0x8e, 0x00, 0x02, 0x10, 0x03, 0x00, 0x96, 0xff, + 0x04, 0x00, 0x02, 0x04, 0x02, 0x05, 0x8c, 0x00, 0x02, 0x12, 0x03, 0x00, + 0x97, 0xff, 0x04, 0x00, 0x03, 0x03, 0x11, 0x09, 0x8b, 0x00, 0x02, 0x13, + 0x03, 0x00, 0x98, 0xff, 0x04, 0x00, 0x02, 0x03, 0x0e, 0x11, 0x8a, 0x00, + 0x02, 0x15, 0x03, 0x00, 0x9a, 0xff, 0x03, 0x02, 0x03, 0x0b, 0x1a, 0x89, + 0x00, 0x02, 0x18, 0x04, 0x00, 0x9b, 0xff, 0x04, 0x05, 0x03, 0x05, 0x02, + 0x07, 0x87, 0x00, 0x02, 0x19, 0x04, 0x00, 0x9c, 0xff, 0x04, 0x00, 0x03, + 0x04, 0x18, 0x0d, 0x86, 0x00, 0x02, 0x1b, 0x04, 0x00, 0x9d, 0xff, 0x04, + 0x00, 0x03, 0x04, 0x12, 0x18, 0x85, 0x00, 0x02, 0x1d, 0x04, 0x00, 0x9f, + 0xff, 0x04, 0x02, 0x04, 0x0d, 0x22, 0x01, 0x83, 0x00, 0x02, 0x1f, 0x04, + 0x00, 0xa0, 0xff, 0x04, 0x05, 0x03, 0x06, 0x25, 0x09, 0x82, 0x00, 0x02, + 0x20, 0x05, 0x00, 0xa1, 0xff, 0x04, 0x00, 0x04, 0x05, 0x1e, 0x12, 0x81, + 0x00, 0x02, 0x22, 0x05, 0x00, 0xa2, 0xff, 0x04, 0x00, 0x03, 0x05, 0x18, + 0x1e, 0x80, 0x00, 0x02, 0x24, 0x05, 0x00, 0xa4, 0xff, 0x08, 0x02, 0x05, + 0x10, 0x2b, 0x01, 0x00, 0x26, 0x05, 0x00, 0xa5, 0xff, 0x07, 0x05, 0x04, + 0x08, 0x2e, 0x0b, 0x32, 0x06, 0x00, 0xa6, 0xff, 0x06, 0x00, 0x04, 0x06, + 0x27, 0x4d, 0x0c, 0x00, 0xa7, 0xff, 0x05, 0x00, 0x03, 0x06, 0x24, 0x17, + 0x00, 0xa9, 0xff, 0x02, 0x03, 0x0e, 0x08, 0xff, 0xff, 0xc7, 0xff, 0xff, + 0x00, 0xdc, 0x00, 0x02, 0x4f, 0xa1, 0x45, 0xa8, 0x00, 0x05, 0x02, 0x8e, + 0xfa, 0xff, 0xee, 0x07, 0xa6, 0x00, 0x01, 0x10, 0xb7, 0x81, 0xff, 0x00, + 0x19, 0xa5, 0x00, 0x01, 0x32, 0xd8, 0x82, 0xff, 0x00, 0x1a, 0xa4, 0x00, + 0x01, 0x5f, 0xed, 0x83, 0xff, 0x00, 0x1a, 0xa2, 0x00, 0x02, 0x02, 0x8e, + 0xfa, 0x84, 0xff, 0x00, 0x1a, 0xa1, 0x00, 0x01, 0x10, 0xb7, 0x86, 0xff, + 0x00, 0x1a, 0xa0, 0x00, 0x01, 0x32, 0xd8, 0x87, 0xff, 0x00, 0x1a, 0x9f, + 0x00, 0x01, 0x5f, 0xed, 0x88, 0xff, 0x00, 0x1a, 0x9d, 0x00, 0x02, 0x02, + 0x8e, 0xfa, 0x89, 0xff, 0x00, 0x1a, 0x9c, 0x00, 0x01, 0x10, 0xb8, 0x8b, + 0xff, 0x00, 0x1a, 0x9b, 0x00, 0x01, 0x32, 0xd8, 0x8c, 0xff, 0x00, 0x1a, + 0x9a, 0x00, 0x01, 0x5f, 0xed, 0x8d, 0xff, 0x00, 0x1a, 0x98, 0x00, 0x02, + 0x02, 0x8e, 0xfa, 0x8e, 0xff, 0x00, 0x1a, 0x97, 0x00, 0x01, 0x10, 0xb9, + 0x90, 0xff, 0x00, 0x1a, 0x96, 0x00, 0x01, 0x33, 0xd9, 0x91, 0xff, 0x00, + 0x1a, 0x95, 0x00, 0x01, 0x61, 0xee, 0x92, 0xff, 0x00, 0x1a, 0x93, 0x00, + 0x02, 0x02, 0x91, 0xfa, 0x93, 0xff, 0x00, 0x1a, 0x92, 0x00, 0x01, 0x07, + 0xbd, 0x95, 0xff, 0x00, 0x1a, 0x91, 0x00, 0x01, 0x01, 0x83, 0x96, 0xff, + 0x00, 0x1a, 0x91, 0x00, 0x01, 0x02, 0x8c, 0x96, 0xff, 0x00, 0x1a, 0x92, + 0x00, 0x01, 0x0e, 0xc7, 0x95, 0xff, 0x00, 0x1a, 0x93, 0x00, 0x02, 0x06, + 0x95, 0xfb, 0x93, 0xff, 0x00, 0x1a, 0x95, 0x00, 0x01, 0x65, 0xf0, 0x92, + 0xff, 0x00, 0x1a, 0x96, 0x00, 0x01, 0x35, 0xde, 0x91, 0xff, 0x00, 0x1a, + 0x97, 0x00, 0x01, 0x11, 0xc1, 0x90, 0xff, 0x00, 0x1a, 0x98, 0x00, 0x02, + 0x02, 0x98, 0xfb, 0x8e, 0xff, 0x00, 0x1a, 0x9a, 0x00, 0x01, 0x67, 0xf1, + 0x8d, 0xff, 0x00, 0x1a, 0x9b, 0x00, 0x01, 0x36, 0xe0, 0x8c, 0xff, 0x00, + 0x1a, 0x9c, 0x00, 0x01, 0x11, 0xc4, 0x8b, 0xff, 0x00, 0x1a, 0x9d, 0x00, + 0x02, 0x02, 0x9b, 0xfc, 0x89, 0xff, 0x00, 0x1a, 0x9f, 0x00, 0x01, 0x69, + 0xf2, 0x88, 0xff, 0x00, 0x1a, 0xa0, 0x00, 0x01, 0x37, 0xe2, 0x87, 0xff, + 0x00, 0x1a, 0xa1, 0x00, 0x01, 0x11, 0xc7, 0x86, 0xff, 0x00, 0x1a, 0xa2, + 0x00, 0x02, 0x02, 0x9e, 0xfc, 0x84, 0xff, 0x00, 0x1a, 0xa4, 0x00, 0x01, + 0x6c, 0xf4, 0x83, 0xff, 0x00, 0x1a, 0xa5, 0x00, 0x01, 0x38, 0xe5, 0x82, + 0xff, 0x00, 0x1a, 0xa6, 0x00, 0x01, 0x12, 0xca, 0x81, 0xff, 0x00, 0x19, + 0xa7, 0x00, 0x05, 0x02, 0xa1, 0xfc, 0xff, 0xe5, 0x05, 0xa9, 0x00, 0x02, + 0x51, 0x93, 0x43, 0xff, 0x00, 0xc7, 0x00, +}; +static EG_EMBEDDED_IMAGE egemb_arrow_left = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_left_data, 2407 }; diff --git a/include/egemb_arrow_right.h b/include/egemb_arrow_right.h new file mode 100644 index 0000000..8843135 --- /dev/null +++ b/include/egemb_arrow_right.h @@ -0,0 +1,201 @@ +static const UINT8 egemb_arrow_right_data[2373] = { + 0xff, 0xff, 0xc8, 0xff, 0x03, 0x00, 0x22, 0x32, 0x00, 0xa9, 0xff, 0x04, + 0x00, 0x36, 0x81, 0x00, 0x00, 0xa8, 0xff, 0x05, 0x00, 0x0f, 0xbe, 0x0a, + 0x00, 0x00, 0xa7, 0xff, 0x04, 0x00, 0x00, 0xad, 0x93, 0x21, 0x80, 0x00, + 0xa5, 0xff, 0x05, 0x00, 0x00, 0x9a, 0x92, 0x95, 0x3a, 0x80, 0x00, 0xa4, + 0xff, 0x06, 0x00, 0x00, 0x91, 0x8a, 0x8b, 0x92, 0x57, 0x80, 0x00, 0xa3, + 0xff, 0x0a, 0x00, 0x00, 0x8a, 0x82, 0x83, 0x85, 0x88, 0x6c, 0x08, 0x00, + 0x00, 0xa2, 0xff, 0x09, 0x00, 0x00, 0x84, 0x79, 0x7b, 0x7c, 0x7f, 0x80, + 0x77, 0x19, 0x80, 0x00, 0xa0, 0xff, 0x0a, 0x00, 0x00, 0x7c, 0x71, 0x73, + 0x74, 0x76, 0x77, 0x79, 0x79, 0x2d, 0x80, 0x00, 0x9f, 0xff, 0x0b, 0x00, + 0x00, 0x74, 0x69, 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x73, 0x76, 0x42, 0x80, + 0x00, 0x9e, 0xff, 0x0f, 0x00, 0x00, 0x6e, 0x61, 0x62, 0x64, 0x65, 0x67, + 0x68, 0x6a, 0x6c, 0x6e, 0x52, 0x07, 0x00, 0x00, 0x9d, 0xff, 0x0e, 0x00, + 0x00, 0x67, 0x58, 0x5a, 0x5b, 0x5d, 0x5e, 0x60, 0x61, 0x63, 0x64, 0x67, + 0x5b, 0x12, 0x80, 0x00, 0x9b, 0xff, 0x0f, 0x00, 0x00, 0x60, 0x50, 0x52, + 0x53, 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x60, 0x5d, 0x20, 0x80, + 0x00, 0x9a, 0xff, 0x10, 0x00, 0x00, 0x59, 0x48, 0x49, 0x4b, 0x4c, 0x4e, + 0x4f, 0x51, 0x52, 0x54, 0x55, 0x57, 0x59, 0x5c, 0x2f, 0x80, 0x00, 0x99, + 0xff, 0x14, 0x00, 0x00, 0x52, 0x40, 0x41, 0x43, 0x44, 0x46, 0x47, 0x49, + 0x4a, 0x4c, 0x4d, 0x4f, 0x50, 0x52, 0x54, 0x3b, 0x05, 0x00, 0x00, 0x98, + 0xff, 0x13, 0x00, 0x01, 0x4d, 0x37, 0x39, 0x3a, 0x3c, 0x3d, 0x3f, 0x40, + 0x42, 0x43, 0x45, 0x46, 0x48, 0x49, 0x4b, 0x4d, 0x43, 0x0c, 0x80, 0x00, + 0x96, 0xff, 0x14, 0x00, 0x02, 0x45, 0x2e, 0x31, 0x32, 0x34, 0x35, 0x37, + 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x42, 0x43, 0x44, 0x46, 0x43, 0x17, + 0x80, 0x00, 0x95, 0xff, 0x15, 0x00, 0x02, 0x3f, 0x26, 0x28, 0x2a, 0x2b, + 0x2d, 0x2e, 0x30, 0x31, 0x33, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x3d, 0x3e, + 0x40, 0x42, 0x1d, 0x80, 0x00, 0x94, 0xff, 0x19, 0x00, 0x03, 0x39, 0x1e, + 0x1f, 0x21, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b, 0x2c, 0x2e, 0x2f, 0x31, + 0x32, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x26, 0x08, 0x06, 0x0b, 0x93, 0xff, + 0x02, 0x00, 0x04, 0x43, 0x83, 0x30, 0x11, 0x31, 0x32, 0x2f, 0x2d, 0x2b, + 0x2a, 0x2a, 0x2d, 0x2d, 0x2f, 0x30, 0x31, 0x32, 0x34, 0x40, 0x3d, 0x2d, + 0x72, 0x92, 0xff, 0x02, 0x00, 0x05, 0x05, 0x85, 0x00, 0x0f, 0x03, 0x06, + 0x0a, 0x0d, 0x0d, 0x09, 0x07, 0x04, 0x02, 0x01, 0x00, 0x03, 0x2d, 0x61, + 0x56, 0xa6, 0x92, 0xff, 0x02, 0x00, 0x05, 0x05, 0x90, 0x00, 0x03, 0x0c, + 0x0c, 0x2a, 0x39, 0x93, 0xff, 0x02, 0x00, 0x06, 0x06, 0x8e, 0x00, 0x04, + 0x04, 0x00, 0x01, 0x00, 0x12, 0x94, 0xff, 0x02, 0x00, 0x07, 0x07, 0x8d, + 0x00, 0x01, 0x07, 0x0c, 0x80, 0x00, 0x95, 0xff, 0x02, 0x00, 0x08, 0x08, + 0x8c, 0x00, 0x01, 0x0d, 0x08, 0x80, 0x00, 0x96, 0xff, 0x02, 0x00, 0x09, + 0x09, 0x8b, 0x00, 0x03, 0x14, 0x06, 0x00, 0x00, 0x98, 0xff, 0x02, 0x00, + 0x0a, 0x0a, 0x89, 0x00, 0x04, 0x06, 0x00, 0x01, 0x00, 0x00, 0x99, 0xff, + 0x02, 0x00, 0x0a, 0x0a, 0x88, 0x00, 0x01, 0x0b, 0x12, 0x80, 0x00, 0x9a, + 0xff, 0x02, 0x00, 0x0b, 0x0b, 0x87, 0x00, 0x01, 0x13, 0x0c, 0x80, 0x00, + 0x9b, 0xff, 0x02, 0x00, 0x0c, 0x0c, 0x85, 0x00, 0x04, 0x01, 0x1c, 0x08, + 0x00, 0x00, 0x9d, 0xff, 0x02, 0x00, 0x0d, 0x0d, 0x84, 0x00, 0x04, 0x08, + 0x1e, 0x01, 0x00, 0x00, 0x9e, 0xff, 0x02, 0x00, 0x0e, 0x0e, 0x83, 0x00, + 0x01, 0x0f, 0x18, 0x80, 0x00, 0x9f, 0xff, 0x02, 0x00, 0x0f, 0x0f, 0x82, + 0x00, 0x01, 0x1a, 0x11, 0x80, 0x00, 0xa0, 0xff, 0x02, 0x00, 0x10, 0x10, + 0x80, 0x00, 0x04, 0x01, 0x24, 0x0a, 0x00, 0x00, 0xa2, 0xff, 0x09, 0x00, + 0x11, 0x11, 0x00, 0x00, 0x0a, 0x27, 0x01, 0x00, 0x00, 0xa3, 0xff, 0x05, + 0x00, 0x11, 0x12, 0x00, 0x14, 0x1f, 0x80, 0x00, 0xa4, 0xff, 0x04, 0x00, + 0x12, 0x1f, 0x21, 0x15, 0x80, 0x00, 0xa5, 0xff, 0x05, 0x00, 0x13, 0x59, + 0x0c, 0x00, 0x00, 0xa7, 0xff, 0x04, 0x00, 0x0a, 0x3e, 0x00, 0x00, 0xa8, + 0xff, 0x03, 0x00, 0x08, 0x1a, 0x00, 0xff, 0xff, 0xda, 0xff, 0xff, 0xff, + 0xc8, 0xff, 0x03, 0x60, 0x64, 0x6f, 0x55, 0xa9, 0xff, 0x04, 0x4b, 0x73, + 0xa7, 0x4d, 0x49, 0xa8, 0xff, 0x05, 0x4d, 0x57, 0xdd, 0x54, 0x4d, 0x4e, + 0xa7, 0xff, 0x07, 0x4d, 0x4d, 0xe2, 0xc2, 0x64, 0x4d, 0x4b, 0x80, 0xa5, + 0xff, 0x08, 0x4d, 0x4d, 0xd2, 0xcf, 0xca, 0x78, 0x4d, 0x4c, 0x4f, 0xa4, + 0xff, 0x09, 0x4d, 0x4d, 0xcb, 0xc8, 0xca, 0xcc, 0x90, 0x4d, 0x4d, 0x49, + 0xa3, 0xff, 0x0a, 0x4d, 0x4d, 0xc6, 0xc2, 0xc3, 0xc5, 0xc7, 0xa4, 0x52, + 0x4d, 0x4d, 0xa2, 0xff, 0x0c, 0x4f, 0x4f, 0xc0, 0xbd, 0xbe, 0xbf, 0xc1, + 0xc2, 0xb1, 0x61, 0x4d, 0x4b, 0x80, 0xa0, 0xff, 0x0d, 0x53, 0x54, 0xbc, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xb8, 0x72, 0x4d, 0x4c, 0x4f, 0x9f, + 0xff, 0x0e, 0x56, 0x58, 0xb9, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb9, + 0xb9, 0x83, 0x4d, 0x4d, 0x49, 0x9e, 0xff, 0x06, 0x59, 0x5d, 0xb5, 0xaf, + 0xb0, 0xb1, 0xb2, 0x80, 0xb3, 0x05, 0xb4, 0xb5, 0x95, 0x54, 0x4d, 0x4d, + 0x9d, 0xff, 0x06, 0x5d, 0x62, 0xb3, 0xac, 0xad, 0xae, 0xae, 0x83, 0xaf, + 0x04, 0xa0, 0x5f, 0x50, 0x4d, 0x80, 0x9b, 0xff, 0x08, 0x60, 0x66, 0xb1, + 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xac, 0x80, 0xab, 0x06, 0xaa, 0xaa, 0xa4, + 0x6e, 0x54, 0x50, 0x4f, 0x9a, 0xff, 0x04, 0x62, 0x6b, 0xb0, 0xa8, 0xa8, + 0x82, 0xa9, 0x09, 0xa8, 0xa7, 0xa6, 0xa5, 0xa5, 0xa3, 0x7b, 0x57, 0x54, + 0x4f, 0x99, 0xff, 0x14, 0x67, 0x70, 0xaf, 0xa6, 0xa7, 0xa7, 0xa8, 0xa7, + 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa1, 0xa0, 0x9e, 0x9d, 0x85, 0x5d, 0x57, + 0x52, 0x98, 0xff, 0x02, 0x68, 0x72, 0xaf, 0x81, 0xa6, 0x0f, 0xa5, 0xa4, + 0xa4, 0xa3, 0xa1, 0xa0, 0x9e, 0x9c, 0x9a, 0x98, 0x97, 0x8a, 0x64, 0x5b, + 0x53, 0x80, 0x96, 0xff, 0x17, 0x6a, 0x76, 0xaf, 0xa5, 0xa6, 0xa6, 0xa5, + 0xa5, 0xa4, 0xa2, 0xa1, 0x9e, 0x9d, 0x9a, 0x98, 0x97, 0x94, 0x92, 0x90, + 0x8a, 0x6c, 0x5d, 0x58, 0x4f, 0x95, 0xff, 0x18, 0x6e, 0x79, 0xb0, 0xa5, + 0xa5, 0xa6, 0xa5, 0xa4, 0xa3, 0xa1, 0x9f, 0x9d, 0x9a, 0x98, 0x95, 0x92, + 0x8f, 0x8e, 0x8b, 0x88, 0x84, 0x6d, 0x5e, 0x5b, 0x51, 0x94, 0xff, 0x02, + 0x6f, 0x7b, 0xb1, 0x80, 0xa6, 0x13, 0xa5, 0xa5, 0xa2, 0xa0, 0x9e, 0x9b, + 0x98, 0x95, 0x92, 0x8f, 0x8b, 0x88, 0x86, 0x83, 0x7f, 0x7d, 0x6f, 0x65, + 0x63, 0x5c, 0x93, 0xff, 0x1a, 0x72, 0x7f, 0xba, 0xb2, 0xb1, 0xaf, 0xaf, + 0xac, 0xa9, 0xa7, 0xa4, 0x9f, 0x9a, 0x95, 0x91, 0x8c, 0x89, 0x85, 0x81, + 0x7e, 0x7a, 0x76, 0x73, 0x7d, 0x86, 0x7c, 0x8e, 0x92, 0xff, 0x1a, 0x74, + 0x82, 0xa6, 0xa4, 0xa3, 0xa1, 0x9e, 0x9b, 0x97, 0x92, 0x8d, 0x89, 0x85, + 0x82, 0x7d, 0x78, 0x6f, 0x67, 0x5f, 0x57, 0x4f, 0x48, 0x43, 0x65, 0x9e, + 0x97, 0xb8, 0x92, 0xff, 0x19, 0x75, 0x83, 0xad, 0xab, 0xaa, 0xa7, 0xa4, + 0xa1, 0x9c, 0x97, 0x92, 0x8c, 0x86, 0x80, 0x7a, 0x73, 0x6d, 0x66, 0x5f, + 0x58, 0x51, 0x4a, 0x5d, 0x70, 0x81, 0x81, 0x93, 0xff, 0x18, 0x77, 0x87, + 0xb4, 0xb2, 0xb0, 0xae, 0xab, 0xa6, 0xa1, 0x9c, 0x96, 0x90, 0x8a, 0x83, + 0x7d, 0x76, 0x6f, 0x68, 0x61, 0x5a, 0x57, 0x60, 0x6e, 0x68, 0x65, 0x94, + 0xff, 0x17, 0x79, 0x88, 0xbb, 0xb9, 0xb7, 0xb4, 0xb0, 0xac, 0xa6, 0xa0, + 0x9a, 0x94, 0x8d, 0x86, 0x7f, 0x78, 0x71, 0x6a, 0x63, 0x63, 0x74, 0x70, + 0x66, 0x4a, 0x95, 0xff, 0x16, 0x7a, 0x8a, 0xc2, 0xc0, 0xbe, 0xba, 0xb6, + 0xb0, 0xaa, 0xa4, 0x9d, 0x96, 0x90, 0x89, 0x81, 0x7a, 0x73, 0x6b, 0x72, + 0x78, 0x72, 0x65, 0x80, 0x96, 0xff, 0x14, 0x7c, 0x8c, 0xc9, 0xc7, 0xc4, + 0xc0, 0xba, 0xb4, 0xae, 0xa7, 0xa0, 0x99, 0x91, 0x8a, 0x83, 0x7b, 0x75, + 0x7f, 0x7a, 0x74, 0x64, 0x98, 0xff, 0x13, 0x7e, 0x8f, 0xd0, 0xcd, 0xca, + 0xc4, 0xbe, 0xb7, 0xb0, 0xa9, 0xa1, 0x9a, 0x92, 0x8b, 0x83, 0x80, 0x86, + 0x7b, 0x75, 0x60, 0x99, 0xff, 0x12, 0x80, 0x8f, 0xd7, 0xd4, 0xce, 0xc7, + 0xc0, 0xb8, 0xb1, 0xaa, 0xa2, 0x9a, 0x93, 0x8b, 0x89, 0x88, 0x7b, 0x73, + 0x59, 0x9a, 0xff, 0x11, 0x80, 0x8f, 0xdc, 0xd7, 0xd0, 0xc8, 0xc0, 0xb8, + 0xb1, 0xa9, 0xa1, 0x9a, 0x92, 0x92, 0x87, 0x7e, 0x70, 0x80, 0x9b, 0xff, + 0x0f, 0x82, 0x91, 0xd6, 0xd2, 0xcc, 0xc5, 0xbe, 0xb6, 0xaf, 0xa7, 0xa0, + 0x98, 0x9a, 0x84, 0x7e, 0x6c, 0x9d, 0xff, 0x0e, 0x83, 0x92, 0xcd, 0xca, + 0xc6, 0xc0, 0xba, 0xb3, 0xac, 0xa4, 0x9f, 0x9b, 0x82, 0x7f, 0x66, 0x9e, + 0xff, 0x0d, 0x86, 0x93, 0xc5, 0xc1, 0xbe, 0xba, 0xb4, 0xae, 0xa7, 0xa4, + 0x96, 0x84, 0x7d, 0x59, 0x9f, 0xff, 0x0c, 0x87, 0x94, 0xbd, 0xb8, 0xb6, + 0xb2, 0xad, 0xa8, 0xa8, 0x90, 0x85, 0x77, 0x80, 0xa0, 0xff, 0x0a, 0x87, + 0x94, 0xb5, 0xaf, 0xad, 0xaa, 0xa6, 0xa8, 0x8b, 0x86, 0x74, 0xa2, 0xff, + 0x03, 0x89, 0x93, 0xac, 0xa5, 0x80, 0xa4, 0x02, 0x87, 0x85, 0x6c, 0xa3, + 0xff, 0x08, 0x89, 0x93, 0xa4, 0x9c, 0xa2, 0x9b, 0x87, 0x85, 0x59, 0xa4, + 0xff, 0x07, 0x8b, 0x94, 0xa1, 0xa1, 0x94, 0x88, 0x7f, 0x80, 0xa5, 0xff, + 0x05, 0x8b, 0x92, 0xb7, 0x8e, 0x89, 0x7d, 0xa7, 0xff, 0x04, 0x7e, 0x8d, + 0xa6, 0x8a, 0x76, 0xa8, 0xff, 0x03, 0x00, 0x85, 0x8f, 0x69, 0xff, 0xff, + 0xda, 0xff, 0xff, 0xff, 0xc8, 0xff, 0x03, 0x00, 0x22, 0x32, 0x00, 0xa9, + 0xff, 0x04, 0x00, 0x36, 0x81, 0x00, 0x00, 0xa8, 0xff, 0x05, 0x00, 0x0f, + 0xbe, 0x0a, 0x00, 0x00, 0xa7, 0xff, 0x04, 0x00, 0x00, 0xad, 0x93, 0x21, + 0x80, 0x00, 0xa5, 0xff, 0x05, 0x00, 0x00, 0x9a, 0x92, 0x95, 0x3a, 0x80, + 0x00, 0xa4, 0xff, 0x06, 0x00, 0x00, 0x91, 0x8a, 0x8b, 0x92, 0x57, 0x80, + 0x00, 0xa3, 0xff, 0x0a, 0x00, 0x00, 0x8a, 0x82, 0x83, 0x85, 0x88, 0x6c, + 0x08, 0x00, 0x00, 0xa2, 0xff, 0x09, 0x00, 0x00, 0x84, 0x79, 0x7b, 0x7c, + 0x7f, 0x80, 0x77, 0x19, 0x80, 0x00, 0xa0, 0xff, 0x0a, 0x00, 0x00, 0x7c, + 0x71, 0x73, 0x74, 0x76, 0x77, 0x79, 0x79, 0x2d, 0x80, 0x00, 0x9f, 0xff, + 0x0b, 0x00, 0x00, 0x74, 0x69, 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x73, 0x76, + 0x42, 0x80, 0x00, 0x9e, 0xff, 0x0f, 0x00, 0x00, 0x6e, 0x61, 0x62, 0x64, + 0x65, 0x67, 0x68, 0x6a, 0x6c, 0x6e, 0x52, 0x07, 0x00, 0x00, 0x9d, 0xff, + 0x0e, 0x00, 0x00, 0x67, 0x58, 0x5a, 0x5b, 0x5d, 0x5e, 0x60, 0x61, 0x63, + 0x64, 0x67, 0x5b, 0x12, 0x80, 0x00, 0x9b, 0xff, 0x0f, 0x00, 0x00, 0x60, + 0x50, 0x52, 0x53, 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x60, 0x5d, + 0x20, 0x80, 0x00, 0x9a, 0xff, 0x10, 0x00, 0x00, 0x59, 0x48, 0x49, 0x4b, + 0x4c, 0x4e, 0x4f, 0x51, 0x52, 0x54, 0x55, 0x57, 0x59, 0x5c, 0x2f, 0x80, + 0x00, 0x99, 0xff, 0x14, 0x00, 0x01, 0x52, 0x40, 0x41, 0x43, 0x44, 0x46, + 0x47, 0x49, 0x4a, 0x4c, 0x4d, 0x4f, 0x50, 0x52, 0x54, 0x3b, 0x06, 0x00, + 0x00, 0x98, 0xff, 0x16, 0x01, 0x02, 0x4d, 0x37, 0x39, 0x3a, 0x3c, 0x3d, + 0x3f, 0x40, 0x42, 0x43, 0x45, 0x46, 0x48, 0x49, 0x4b, 0x4d, 0x43, 0x0d, + 0x01, 0x00, 0x00, 0x96, 0xff, 0x17, 0x01, 0x03, 0x45, 0x2e, 0x31, 0x32, + 0x34, 0x35, 0x37, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x42, 0x43, 0x44, + 0x46, 0x43, 0x18, 0x01, 0x01, 0x00, 0x95, 0xff, 0x18, 0x01, 0x03, 0x3f, + 0x26, 0x28, 0x2a, 0x2b, 0x2d, 0x2e, 0x30, 0x31, 0x33, 0x34, 0x36, 0x37, + 0x39, 0x3a, 0x3d, 0x3e, 0x40, 0x42, 0x1e, 0x01, 0x01, 0x00, 0x94, 0xff, + 0x19, 0x01, 0x04, 0x39, 0x1e, 0x1f, 0x21, 0x23, 0x25, 0x26, 0x28, 0x29, + 0x2b, 0x2c, 0x2e, 0x2f, 0x31, 0x32, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x26, + 0x09, 0x07, 0x0b, 0x93, 0xff, 0x02, 0x01, 0x06, 0x43, 0x83, 0x30, 0x11, + 0x31, 0x32, 0x2f, 0x2d, 0x2b, 0x2a, 0x2a, 0x2d, 0x2d, 0x2f, 0x30, 0x31, + 0x32, 0x34, 0x40, 0x3f, 0x2e, 0x72, 0x92, 0xff, 0x02, 0x01, 0x07, 0x05, + 0x85, 0x00, 0x0f, 0x03, 0x06, 0x0a, 0x0d, 0x0d, 0x09, 0x07, 0x04, 0x02, + 0x01, 0x00, 0x03, 0x2d, 0x62, 0x57, 0xa6, 0x92, 0xff, 0x02, 0x01, 0x07, + 0x05, 0x90, 0x00, 0x03, 0x0d, 0x0e, 0x2c, 0x3c, 0x93, 0xff, 0x02, 0x01, + 0x08, 0x06, 0x8e, 0x00, 0x04, 0x04, 0x01, 0x03, 0x02, 0x12, 0x94, 0xff, + 0x02, 0x01, 0x0a, 0x07, 0x8d, 0x00, 0x04, 0x07, 0x0e, 0x03, 0x03, 0x00, + 0x95, 0xff, 0x02, 0x03, 0x0b, 0x08, 0x8c, 0x00, 0x04, 0x0e, 0x0b, 0x03, + 0x02, 0x00, 0x96, 0xff, 0x02, 0x03, 0x0c, 0x09, 0x8b, 0x00, 0x03, 0x15, + 0x09, 0x03, 0x03, 0x98, 0xff, 0x02, 0x03, 0x0d, 0x0a, 0x89, 0x00, 0x04, + 0x06, 0x02, 0x04, 0x02, 0x00, 0x99, 0xff, 0x02, 0x03, 0x0e, 0x0a, 0x88, + 0x00, 0x04, 0x0b, 0x15, 0x04, 0x03, 0x00, 0x9a, 0xff, 0x02, 0x03, 0x0f, + 0x0b, 0x87, 0x00, 0x04, 0x14, 0x10, 0x04, 0x02, 0x00, 0x9b, 0xff, 0x02, + 0x03, 0x10, 0x0c, 0x85, 0x00, 0x04, 0x01, 0x1e, 0x0c, 0x04, 0x02, 0x9d, + 0xff, 0x02, 0x03, 0x11, 0x0d, 0x84, 0x00, 0x04, 0x08, 0x20, 0x05, 0x03, + 0x05, 0x9e, 0xff, 0x02, 0x03, 0x12, 0x0e, 0x83, 0x00, 0x04, 0x0f, 0x1b, + 0x04, 0x04, 0x00, 0x9f, 0xff, 0x02, 0x03, 0x14, 0x0f, 0x82, 0x00, 0x04, + 0x1b, 0x16, 0x05, 0x03, 0x00, 0xa0, 0xff, 0x02, 0x04, 0x15, 0x10, 0x80, + 0x00, 0x04, 0x01, 0x26, 0x0f, 0x04, 0x02, 0xa2, 0xff, 0x09, 0x04, 0x16, + 0x11, 0x00, 0x00, 0x0a, 0x29, 0x06, 0x04, 0x05, 0xa3, 0xff, 0x08, 0x04, + 0x16, 0x12, 0x00, 0x14, 0x22, 0x05, 0x04, 0x00, 0xa4, 0xff, 0x07, 0x04, + 0x18, 0x19, 0x22, 0x1a, 0x05, 0x03, 0x00, 0xa5, 0xff, 0x05, 0x04, 0x18, + 0x49, 0x12, 0x05, 0x02, 0xa7, 0xff, 0x04, 0x02, 0x0c, 0x25, 0x06, 0x04, + 0xa8, 0xff, 0x03, 0x00, 0x08, 0x11, 0x00, 0xff, 0xff, 0xda, 0xff, 0xff, + 0x00, 0xc8, 0x00, 0x03, 0x08, 0x87, 0x9a, 0x0f, 0xa9, 0x00, 0x04, 0x7e, + 0xff, 0xff, 0xd8, 0x32, 0xa8, 0x00, 0x00, 0xae, 0x80, 0xff, 0x01, 0xed, + 0x5e, 0xa7, 0x00, 0x00, 0xaf, 0x81, 0xff, 0x02, 0xfa, 0x8e, 0x02, 0xa5, + 0x00, 0x00, 0xaf, 0x83, 0xff, 0x01, 0xb7, 0x10, 0xa4, 0x00, 0x00, 0xaf, + 0x84, 0xff, 0x01, 0xd8, 0x32, 0xa3, 0x00, 0x00, 0xaf, 0x85, 0xff, 0x01, + 0xed, 0x5f, 0xa2, 0x00, 0x00, 0xaf, 0x86, 0xff, 0x02, 0xfa, 0x8e, 0x02, + 0xa0, 0x00, 0x00, 0xaf, 0x88, 0xff, 0x01, 0xb8, 0x10, 0x9f, 0x00, 0x00, + 0xaf, 0x89, 0xff, 0x01, 0xd8, 0x32, 0x9e, 0x00, 0x00, 0xaf, 0x8a, 0xff, + 0x01, 0xed, 0x5f, 0x9d, 0x00, 0x00, 0xaf, 0x8b, 0xff, 0x02, 0xfa, 0x8e, + 0x02, 0x9b, 0x00, 0x00, 0xaf, 0x8d, 0xff, 0x01, 0xb8, 0x10, 0x9a, 0x00, + 0x00, 0xaf, 0x8e, 0xff, 0x01, 0xd8, 0x32, 0x99, 0x00, 0x00, 0xb0, 0x8f, + 0xff, 0x01, 0xed, 0x60, 0x98, 0x00, 0x00, 0xb1, 0x90, 0xff, 0x02, 0xfa, + 0x90, 0x02, 0x96, 0x00, 0x00, 0xb2, 0x92, 0xff, 0x01, 0xbb, 0x10, 0x95, + 0x00, 0x00, 0xb2, 0x93, 0xff, 0x01, 0xda, 0x34, 0x94, 0x00, 0x00, 0xb3, + 0x94, 0xff, 0x01, 0xef, 0x5d, 0x93, 0x00, 0x00, 0xb4, 0x95, 0xff, 0x01, + 0xe6, 0x09, 0x92, 0x00, 0x00, 0xb5, 0x95, 0xff, 0x01, 0xea, 0x0e, 0x92, + 0x00, 0x00, 0xb5, 0x94, 0xff, 0x02, 0xf2, 0x6a, 0x02, 0x92, 0x00, 0x00, + 0xb6, 0x93, 0xff, 0x02, 0xdd, 0x37, 0x02, 0x93, 0x00, 0x00, 0xb7, 0x92, + 0xff, 0x01, 0xc0, 0x11, 0x95, 0x00, 0x00, 0xb7, 0x90, 0xff, 0x02, 0xfb, + 0x96, 0x02, 0x96, 0x00, 0x00, 0xb8, 0x8f, 0xff, 0x01, 0xf1, 0x66, 0x98, + 0x00, 0x00, 0xb9, 0x8e, 0xff, 0x01, 0xdf, 0x35, 0x99, 0x00, 0x00, 0xba, + 0x8d, 0xff, 0x01, 0xc3, 0x11, 0x9a, 0x00, 0x00, 0xbb, 0x8b, 0xff, 0x02, + 0xfb, 0x99, 0x02, 0x9b, 0x00, 0x00, 0xbc, 0x8a, 0xff, 0x01, 0xf2, 0x68, + 0x9d, 0x00, 0x00, 0xbc, 0x89, 0xff, 0x01, 0xe1, 0x37, 0x9e, 0x00, 0x00, + 0xbd, 0x88, 0xff, 0x01, 0xc5, 0x11, 0x9f, 0x00, 0x00, 0xbe, 0x86, 0xff, + 0x02, 0xfc, 0x9c, 0x02, 0xa0, 0x00, 0x00, 0xbe, 0x85, 0xff, 0x01, 0xf3, + 0x6a, 0xa2, 0x00, 0x00, 0xbf, 0x84, 0xff, 0x01, 0xe4, 0x38, 0xa3, 0x00, + 0x00, 0xc0, 0x83, 0xff, 0x01, 0xc8, 0x11, 0xa4, 0x00, 0x00, 0xc1, 0x81, + 0xff, 0x02, 0xfc, 0x9f, 0x02, 0xa5, 0x00, 0x00, 0xc1, 0x80, 0xff, 0x01, + 0xf4, 0x6c, 0xa7, 0x00, 0x04, 0x73, 0xfe, 0xff, 0xe6, 0x39, 0xa8, 0x00, + 0x03, 0x01, 0x86, 0x87, 0x11, 0xff, 0x00, 0xda, 0x00, +}; +static EG_EMBEDDED_IMAGE egemb_arrow_right = { 48, 48, EG_EIPIXELMODE_COLOR_ALPHA, EG_EICOMPMODE_RLE, egemb_arrow_right_data, 2373 }; diff --git a/include/egemb_back_selected_small.h b/include/egemb_back_selected_small.h new file mode 100644 index 0000000..c03d8b7 --- /dev/null +++ b/include/egemb_back_selected_small.h @@ -0,0 +1,129 @@ +static const UINT8 egemb_back_selected_small_data[1503] = { + 0x83, 0xbf, 0x02, 0xc8, 0xd2, 0xd6, 0xab, 0xdc, 0x02, 0xd6, 0xd2, 0xc8, + 0x87, 0xbf, 0x01, 0xc3, 0xd6, 0x80, 0xdc, 0x04, 0xdb, 0xd7, 0xd5, 0xd3, + 0xd1, 0xa1, 0xd0, 0x04, 0xd1, 0xd3, 0xd5, 0xd7, 0xdb, 0x80, 0xdc, 0x01, + 0xd6, 0xc3, 0x84, 0xbf, 0x0b, 0xcc, 0xdb, 0xdc, 0xdc, 0xd5, 0xcd, 0xc7, + 0xc3, 0xbf, 0xbe, 0xbd, 0xbc, 0x9f, 0xbb, 0x0b, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc3, 0xc7, 0xcd, 0xd5, 0xdc, 0xdc, 0xdb, 0xcc, 0x82, 0xbf, 0x0c, 0xcf, + 0xdc, 0xdc, 0xd7, 0xcc, 0xc3, 0xba, 0xb4, 0xb0, 0xad, 0xac, 0xaa, 0xaa, + 0x9f, 0xa9, 0x0c, 0xaa, 0xaa, 0xac, 0xad, 0xb0, 0xb4, 0xba, 0xc3, 0xcc, + 0xd7, 0xdc, 0xdc, 0xcf, 0x80, 0xbf, 0x0d, 0xc9, 0xdc, 0xdc, 0xd5, 0xc8, + 0xbc, 0xb2, 0xaa, 0xa3, 0x9f, 0x9d, 0x9c, 0x9b, 0x9a, 0x9f, 0x99, 0x1c, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9f, 0xa3, 0xaa, 0xb2, 0xbc, 0xc8, 0xd5, 0xdc, + 0xdc, 0xc9, 0xbf, 0xc0, 0xd9, 0xdc, 0xd7, 0xc8, 0xb9, 0xad, 0xa3, 0x9b, + 0x96, 0x92, 0x90, 0x8e, 0x8e, 0xa1, 0x8d, 0x1b, 0x8e, 0x8e, 0x90, 0x92, + 0x96, 0x9b, 0xa3, 0xad, 0xb9, 0xc8, 0xd7, 0xdc, 0xd8, 0xc0, 0xc9, 0xdc, + 0xdc, 0xcb, 0xbb, 0xad, 0xa1, 0x97, 0x8f, 0x8a, 0x87, 0x85, 0x84, 0x83, + 0xa1, 0x82, 0x1a, 0x83, 0x84, 0x85, 0x87, 0x8a, 0x8f, 0x97, 0xa1, 0xad, + 0xbb, 0xcb, 0xdc, 0xdc, 0xc9, 0xd2, 0xdc, 0xd4, 0xc2, 0xb2, 0xa3, 0x97, + 0x8d, 0x86, 0x81, 0x7e, 0x7c, 0x7c, 0xa3, 0x7b, 0x18, 0x7c, 0x7c, 0x7e, + 0x81, 0x86, 0x8d, 0x97, 0xa3, 0xb2, 0xc2, 0xd4, 0xdc, 0xd2, 0xd8, 0xdc, + 0xcc, 0xba, 0xa9, 0x9b, 0x8f, 0x86, 0x7f, 0x7a, 0x78, 0x77, 0x80, 0x76, + 0x9f, 0x75, 0x80, 0x76, 0x17, 0x77, 0x78, 0x7a, 0x7f, 0x86, 0x8f, 0x9b, + 0xa9, 0xba, 0xcc, 0xdc, 0xd8, 0xda, 0xdb, 0xc6, 0xb4, 0xa3, 0x95, 0x8a, + 0x81, 0x7a, 0x76, 0x74, 0x74, 0xa5, 0x73, 0x16, 0x74, 0x74, 0x76, 0x7a, + 0x80, 0x8a, 0x95, 0xa3, 0xb4, 0xc6, 0xdb, 0xdb, 0xdc, 0xd7, 0xc3, 0xaf, + 0x9f, 0x91, 0x86, 0x7d, 0x78, 0x74, 0x74, 0xa7, 0x73, 0x14, 0x74, 0x74, + 0x78, 0x7d, 0x86, 0x91, 0x9f, 0xaf, 0xc2, 0xd7, 0xdc, 0xdc, 0xd4, 0xbf, + 0xad, 0x9d, 0x90, 0x85, 0x7c, 0x77, 0x74, 0xa9, 0x73, 0x12, 0x74, 0x77, + 0x7c, 0x85, 0x90, 0x9d, 0xad, 0xbf, 0xd4, 0xdc, 0xdc, 0xd3, 0xbe, 0xac, + 0x9b, 0x8e, 0x83, 0x7c, 0x76, 0xab, 0x73, 0x11, 0x76, 0x7c, 0x83, 0x8e, + 0x9b, 0xab, 0xbe, 0xd3, 0xdc, 0xdc, 0xd1, 0xbc, 0xaa, 0x9b, 0x8d, 0x83, + 0x7b, 0x76, 0xab, 0x73, 0x11, 0x76, 0x7b, 0x83, 0x8d, 0x9b, 0xaa, 0xbc, + 0xd1, 0xdc, 0xdc, 0xd0, 0xbc, 0xaa, 0x9a, 0x8d, 0x82, 0x7b, 0x76, 0xab, + 0x73, 0x11, 0x76, 0x7b, 0x82, 0x8d, 0x9a, 0xaa, 0xbc, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, + 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, + 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, + 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, + 0xd0, 0xbb, 0xa9, 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, + 0x7b, 0x82, 0x8d, 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbb, 0xa9, + 0x99, 0x8d, 0x82, 0x7b, 0x75, 0xab, 0x73, 0x11, 0x75, 0x7b, 0x82, 0x8d, + 0x99, 0xa9, 0xbb, 0xd0, 0xdc, 0xdc, 0xd0, 0xbc, 0xaa, 0x9a, 0x8d, 0x82, + 0x7b, 0x76, 0xab, 0x73, 0x11, 0x76, 0x7b, 0x82, 0x8d, 0x9a, 0xaa, 0xbc, + 0xd0, 0xdc, 0xdc, 0xd1, 0xbc, 0xaa, 0x9b, 0x8d, 0x83, 0x7b, 0x76, 0xab, + 0x73, 0x11, 0x76, 0x7b, 0x83, 0x8d, 0x9b, 0xaa, 0xbc, 0xd1, 0xdc, 0xdc, + 0xd3, 0xbe, 0xac, 0x9b, 0x8e, 0x83, 0x7c, 0x76, 0xab, 0x73, 0x12, 0x76, + 0x7c, 0x83, 0x8e, 0x9b, 0xab, 0xbe, 0xd3, 0xdc, 0xdc, 0xd4, 0xbf, 0xad, + 0x9d, 0x90, 0x85, 0x7c, 0x77, 0x74, 0xa9, 0x73, 0x14, 0x74, 0x77, 0x7c, + 0x85, 0x90, 0x9d, 0xad, 0xbf, 0xd4, 0xdc, 0xdc, 0xd7, 0xc2, 0xaf, 0x9f, + 0x91, 0x86, 0x7d, 0x78, 0x74, 0x74, 0xa7, 0x73, 0x16, 0x74, 0x74, 0x78, + 0x7d, 0x86, 0x91, 0x9f, 0xaf, 0xc2, 0xd7, 0xdc, 0xda, 0xdb, 0xc6, 0xb4, + 0xa3, 0x95, 0x8a, 0x80, 0x7a, 0x76, 0x74, 0x74, 0xa5, 0x73, 0x17, 0x74, + 0x74, 0x76, 0x7a, 0x80, 0x8a, 0x95, 0xa3, 0xb4, 0xc6, 0xdb, 0xdb, 0xd8, + 0xdc, 0xcc, 0xba, 0xa9, 0x9b, 0x8f, 0x86, 0x7f, 0x7a, 0x78, 0x77, 0x80, + 0x76, 0x9f, 0x75, 0x80, 0x76, 0x18, 0x77, 0x78, 0x7a, 0x7f, 0x86, 0x8f, + 0x9b, 0xa9, 0xba, 0xcc, 0xdc, 0xd8, 0xd2, 0xdc, 0xd4, 0xc2, 0xb1, 0xa3, + 0x97, 0x8d, 0x86, 0x81, 0x7e, 0x7c, 0x7c, 0xa3, 0x7b, 0x1a, 0x7c, 0x7c, + 0x7e, 0x81, 0x86, 0x8d, 0x97, 0xa3, 0xb1, 0xc2, 0xd4, 0xdc, 0xd2, 0xc9, + 0xdc, 0xdc, 0xcb, 0xbb, 0xad, 0xa1, 0x97, 0x8f, 0x8a, 0x87, 0x85, 0x84, + 0x83, 0xa1, 0x82, 0x1b, 0x83, 0x84, 0x85, 0x86, 0x8a, 0x8f, 0x97, 0xa1, + 0xad, 0xbb, 0xcb, 0xdc, 0xdc, 0xc9, 0xc0, 0xd8, 0xdc, 0xd6, 0xc8, 0xb9, + 0xad, 0xa3, 0x9b, 0x95, 0x92, 0x90, 0x8e, 0x8e, 0xa1, 0x8d, 0x1c, 0x8e, + 0x8e, 0x90, 0x92, 0x95, 0x9b, 0xa3, 0xad, 0xb9, 0xc8, 0xd6, 0xdc, 0xd8, + 0xc0, 0xbf, 0xc9, 0xdc, 0xdc, 0xd5, 0xc8, 0xbb, 0xb2, 0xa9, 0xa3, 0x9f, + 0x9d, 0x9c, 0x9b, 0x9a, 0x9f, 0x99, 0x0d, 0x9a, 0x9b, 0x9c, 0x9d, 0x9f, + 0xa3, 0xa9, 0xb2, 0xbb, 0xc8, 0xd5, 0xdc, 0xdc, 0xc9, 0x80, 0xbf, 0x0c, + 0xcf, 0xdc, 0xdc, 0xd7, 0xcc, 0xc2, 0xba, 0xb4, 0xb0, 0xad, 0xac, 0xaa, + 0xaa, 0x9f, 0xa9, 0x0c, 0xaa, 0xaa, 0xac, 0xad, 0xb0, 0xb4, 0xba, 0xc2, + 0xcc, 0xd7, 0xdc, 0xdc, 0xcf, 0x82, 0xbf, 0x0b, 0xcd, 0xdb, 0xdc, 0xdc, + 0xd5, 0xcd, 0xc7, 0xc3, 0xbf, 0xbe, 0xbc, 0xbc, 0x9f, 0xbb, 0x0b, 0xbc, + 0xbc, 0xbe, 0xbf, 0xc3, 0xc7, 0xcc, 0xd5, 0xdc, 0xdc, 0xdb, 0xcd, 0x84, + 0xbf, 0x01, 0xc3, 0xd6, 0x80, 0xdc, 0x04, 0xdb, 0xd7, 0xd5, 0xd3, 0xd1, + 0xa1, 0xd0, 0x04, 0xd1, 0xd3, 0xd5, 0xd7, 0xdb, 0x80, 0xdc, 0x01, 0xd6, + 0xc4, 0x87, 0xbf, 0x02, 0xc9, 0xd2, 0xd6, 0xab, 0xdc, 0x02, 0xd6, 0xd2, + 0xc9, 0x83, 0xbf, +}; +static EG_EMBEDDED_IMAGE egemb_back_selected_small = { 64, 64, EG_EIPIXELMODE_GRAY, EG_EICOMPMODE_RLE, egemb_back_selected_small_data, 1503 }; diff --git a/include/egemb_refind_banner.h b/include/egemb_refind_banner.h new file mode 100644 index 0000000..7482cbc --- /dev/null +++ b/include/egemb_refind_banner.h @@ -0,0 +1,636 @@ +static const UINT8 egemb_refind_banner_data[7592] = { + 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0, 0x8e, 0xc0, 0x08, 0xb2, 0x98, 0x83, 0x6e, 0x5a, + 0x45, 0x30, 0x1b, 0x39, 0xa8, 0xc0, 0x00, 0x26, 0x8c, 0x00, 0x00, 0x49, + 0x81, 0xc0, 0x00, 0x53, 0x8c, 0x00, 0x03, 0x0d, 0xc0, 0xa1, 0x02, 0x84, + 0x00, 0x00, 0x13, 0x9f, 0xc0, 0x01, 0x6e, 0x0b, 0x83, 0x00, 0x00, 0x5a, + 0xa8, 0xc0, 0x01, 0xb9, 0x1d, 0x8b, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, + 0xbf, 0x45, 0x8b, 0x00, 0x03, 0x04, 0xc0, 0xc0, 0x90, 0x83, 0x00, 0x01, + 0x41, 0xb5, 0xa0, 0xc0, 0x01, 0xb9, 0x15, 0x82, 0x00, 0x00, 0x82, 0xa9, + 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x09, 0x11, 0x80, 0xa6, 0xa6, 0x91, 0x70, + 0x22, 0x00, 0x00, 0x38, 0x82, 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x0d, 0x0b, + 0x75, 0xa0, 0xab, 0x9a, 0x82, 0x41, 0x04, 0x00, 0x00, 0xbb, 0xc0, 0xbe, + 0x07, 0x82, 0x00, 0x00, 0xa3, 0xa2, 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00, + 0xaa, 0xa9, 0xc0, 0x00, 0x38, 0x82, 0x00, 0x00, 0x73, 0x82, 0xc0, 0x03, + 0xbf, 0x66, 0x00, 0x2f, 0x82, 0xc0, 0x00, 0x65, 0x82, 0x00, 0x00, 0x56, + 0x83, 0xc0, 0x05, 0x9d, 0x11, 0x00, 0xb2, 0xc0, 0xb2, 0x82, 0x00, 0x00, + 0x1d, 0xa2, 0xc0, 0x00, 0xad, 0x82, 0x00, 0x01, 0x11, 0xbf, 0xa9, 0xc0, + 0x00, 0x14, 0x82, 0x00, 0x00, 0xac, 0x80, 0xc0, 0x05, 0xb4, 0x04, 0xc0, + 0xc0, 0x48, 0x26, 0x82, 0xc0, 0x00, 0x40, 0x82, 0x00, 0x00, 0x84, 0x80, + 0xc0, 0x08, 0xb1, 0x0b, 0xc0, 0xc0, 0x91, 0x00, 0xa9, 0xc0, 0x8e, 0x82, + 0x00, 0x00, 0x47, 0xa2, 0xc0, 0x00, 0x85, 0x82, 0x00, 0x00, 0x3a, 0x98, + 0xc0, 0x11, 0xb3, 0x95, 0x7a, 0x60, 0x45, 0x2a, 0x0f, 0x66, 0xc0, 0xc0, + 0xa4, 0x58, 0x20, 0x0b, 0x69, 0xc0, 0xc0, 0xac, 0x82, 0x00, 0x00, 0x1a, + 0x80, 0xc0, 0x06, 0xb2, 0x46, 0x00, 0xc0, 0xc0, 0x97, 0x1d, 0x82, 0xc0, + 0x00, 0x18, 0x82, 0x00, 0x0c, 0xb0, 0xc0, 0xc0, 0xb7, 0x54, 0x00, 0xc0, + 0xc0, 0xbf, 0x3d, 0xa6, 0xc0, 0x67, 0x82, 0x00, 0x14, 0x6d, 0xc0, 0xc0, + 0xaf, 0x91, 0x77, 0x5d, 0x42, 0x28, 0x0e, 0x91, 0xc0, 0xc0, 0xb4, 0x70, + 0x34, 0x15, 0x05, 0x17, 0x53, 0xb5, 0x87, 0xc0, 0x04, 0x9d, 0x60, 0x2e, + 0x16, 0x08, 0x85, 0x00, 0x00, 0x63, 0x98, 0xc0, 0x00, 0x68, 0x83, 0x00, + 0x0a, 0x16, 0xc0, 0x6f, 0x05, 0x00, 0x00, 0x09, 0xb5, 0xc0, 0xc0, 0x85, + 0x82, 0x00, 0x0a, 0x08, 0x1d, 0x1d, 0x14, 0x02, 0x00, 0x00, 0xc0, 0xc0, + 0xbf, 0xa6, 0x81, 0xc0, 0x00, 0xb1, 0x82, 0x00, 0x06, 0x01, 0x1d, 0x1d, + 0x15, 0x04, 0x00, 0x00, 0x83, 0xc0, 0x00, 0x41, 0x82, 0x00, 0x03, 0x93, + 0xc0, 0xc0, 0x51, 0x83, 0x00, 0x03, 0x5d, 0xbe, 0x6d, 0x0e, 0x83, 0x00, + 0x00, 0x4a, 0x85, 0xc0, 0x01, 0xa7, 0x3c, 0x8a, 0x00, 0x00, 0x8b, 0x99, + 0xc0, 0x00, 0x87, 0x82, 0x00, 0x01, 0x05, 0x6e, 0x81, 0x00, 0x00, 0x54, + 0x80, 0xc0, 0x00, 0x5e, 0x89, 0x00, 0x85, 0xc0, 0x00, 0x8a, 0x89, 0x00, + 0x83, 0xc0, 0x00, 0x1a, 0x81, 0x00, 0x01, 0x01, 0xb7, 0x80, 0xc0, 0x00, + 0x68, 0x82, 0x00, 0x01, 0x42, 0x39, 0x85, 0x00, 0x00, 0x0f, 0x84, 0xc0, + 0x01, 0x8f, 0x0e, 0x84, 0x00, 0x01, 0x12, 0x02, 0x82, 0x00, 0x00, 0xb2, + 0x99, 0xc0, 0x00, 0xb8, 0x82, 0x00, 0x06, 0x02, 0x02, 0x0e, 0x31, 0x14, + 0x02, 0xa7, 0x80, 0xc0, 0x00, 0x36, 0x89, 0x00, 0x85, 0xc0, 0x00, 0x63, + 0x89, 0x00, 0x82, 0xc0, 0x00, 0xb4, 0x82, 0x00, 0x00, 0x1f, 0x81, 0xc0, + 0x00, 0x8b, 0x84, 0x00, 0x02, 0x2c, 0x62, 0x3a, 0x82, 0x00, 0x00, 0x12, + 0x83, 0xc0, 0x01, 0x99, 0x06, 0x82, 0x00, 0x04, 0x1b, 0x84, 0xb2, 0xb5, + 0x01, 0x81, 0x00, 0x00, 0x1a, 0x9a, 0xc0, 0x00, 0xa2, 0x83, 0x00, 0x04, + 0x38, 0xb8, 0xc0, 0xbd, 0x8a, 0x80, 0xc0, 0x01, 0xbf, 0x0f, 0x82, 0x00, + 0x06, 0x91, 0xb5, 0xb6, 0x9e, 0x58, 0x02, 0x00, 0x85, 0xc0, 0x00, 0x3b, + 0x82, 0x00, 0x06, 0x6d, 0xb3, 0xb8, 0x9f, 0x54, 0x00, 0x00, 0x82, 0xc0, + 0x00, 0x8e, 0x82, 0x00, 0x00, 0x45, 0x81, 0xc0, 0x00, 0x72, 0x83, 0x00, + 0x03, 0x4c, 0xbe, 0xc0, 0xb2, 0x82, 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, + 0xb2, 0x14, 0x82, 0x00, 0x04, 0x4e, 0xba, 0xc0, 0xc0, 0x8d, 0x82, 0x00, + 0x00, 0x42, 0x9a, 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x01, 0x07, 0xaf, 0x84, + 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x01, 0x0d, 0xbf, 0x81, 0xc0, 0x01, 0x6c, + 0x00, 0x85, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0xa3, 0x81, 0xc0, 0x01, + 0x57, 0x00, 0x82, 0xc0, 0x00, 0x68, 0x82, 0x00, 0x00, 0x6b, 0x81, 0xc0, + 0x00, 0x4e, 0x82, 0x00, 0x04, 0x16, 0xbb, 0xc0, 0xc0, 0xa7, 0x82, 0x00, + 0x00, 0x59, 0x82, 0xc0, 0x00, 0x54, 0x82, 0x00, 0x01, 0x3b, 0xbe, 0x80, + 0xc0, 0x00, 0x63, 0x82, 0x00, 0x00, 0x6b, 0x9a, 0xc0, 0x00, 0x52, 0x82, + 0x00, 0x00, 0x45, 0x85, 0xc0, 0x00, 0x81, 0x82, 0x00, 0x00, 0x35, 0x82, + 0xc0, 0x01, 0xb6, 0x04, 0x84, 0xc0, 0x00, 0xac, 0x82, 0x00, 0x01, 0x0b, + 0xbe, 0x81, 0xc0, 0x01, 0xa2, 0x00, 0x82, 0xc0, 0x00, 0x42, 0x82, 0x00, + 0x00, 0x91, 0x81, 0xc0, 0x00, 0x28, 0x82, 0x00, 0x00, 0x6f, 0x80, 0xc0, + 0x00, 0x78, 0x82, 0x00, 0x00, 0x8a, 0x81, 0xc0, 0x01, 0xab, 0x04, 0x81, + 0x00, 0x01, 0x08, 0xac, 0x81, 0xc0, 0x00, 0x3a, 0x82, 0x00, 0x00, 0x93, + 0x9a, 0xc0, 0x00, 0x29, 0x82, 0x00, 0x00, 0x79, 0x85, 0xc0, 0x00, 0x59, + 0x82, 0x00, 0x00, 0x5f, 0x83, 0xc0, 0x00, 0xbd, 0x84, 0xc0, 0x00, 0x85, + 0x82, 0x00, 0x00, 0x31, 0x82, 0xc0, 0x01, 0xbf, 0xa8, 0x82, 0xc0, 0x00, + 0x1a, 0x82, 0x00, 0x00, 0xb5, 0x80, 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, + 0x00, 0xaf, 0x80, 0xc0, 0x00, 0x40, 0x81, 0x00, 0x01, 0x04, 0xb8, 0x81, + 0xc0, 0x00, 0x6b, 0x82, 0x00, 0x00, 0x51, 0x81, 0xc0, 0x01, 0xbf, 0x11, + 0x81, 0x00, 0x01, 0x02, 0xb8, 0x99, 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, + 0x00, 0xa8, 0x85, 0xc0, 0x00, 0x32, 0x82, 0x00, 0x00, 0x88, 0x86, 0xc0, + 0x01, 0xa3, 0x4a, 0x80, 0xc0, 0x00, 0x5e, 0x82, 0x00, 0x00, 0x57, 0x88, + 0xc0, 0x00, 0xb4, 0x82, 0x00, 0x00, 0x1d, 0x81, 0xc0, 0x00, 0x9b, 0x82, + 0x00, 0x00, 0x25, 0x80, 0xc0, 0x01, 0xbc, 0x0b, 0x81, 0x00, 0x00, 0x2f, + 0x82, 0xc0, 0x00, 0x31, 0x82, 0x00, 0x00, 0x8f, 0x81, 0xc0, 0x00, 0xa8, + 0x82, 0x00, 0x00, 0x23, 0x9a, 0xc0, 0x00, 0x99, 0x82, 0x00, 0x01, 0x10, + 0xbf, 0x84, 0xc0, 0x01, 0xbe, 0x0b, 0x82, 0x00, 0x00, 0xaf, 0x85, 0xc0, + 0x02, 0xb3, 0x1d, 0x60, 0x80, 0xc0, 0x00, 0x36, 0x82, 0x00, 0x00, 0x7f, + 0x88, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x43, 0x81, 0xc0, 0x00, 0x75, + 0x82, 0x00, 0x00, 0x57, 0x80, 0xc0, 0x00, 0x91, 0x82, 0x00, 0x00, 0x62, + 0x82, 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00, 0xaf, 0x81, 0xc0, 0x00, 0x7f, + 0x82, 0x00, 0x00, 0x4b, 0x9a, 0xc0, 0x00, 0x6f, 0x82, 0x00, 0x00, 0x39, + 0x85, 0xc0, 0x00, 0xa3, 0x82, 0x00, 0x01, 0x0c, 0xbf, 0x84, 0xc0, 0x07, + 0xb8, 0x33, 0x08, 0xb2, 0xc0, 0xc0, 0xbf, 0x0f, 0x82, 0x00, 0x00, 0xa6, + 0x88, 0xc0, 0x00, 0x68, 0x82, 0x00, 0x00, 0x69, 0x81, 0xc0, 0x00, 0x4e, + 0x82, 0x00, 0x00, 0x81, 0x80, 0xc0, 0x00, 0x5a, 0x82, 0x00, 0x00, 0x8f, + 0x82, 0xc0, 0x00, 0x05, 0x82, 0x00, 0x00, 0xb7, 0x81, 0xc0, 0x00, 0x55, + 0x82, 0x00, 0x00, 0x73, 0x9a, 0xc0, 0x00, 0x47, 0x82, 0x00, 0x00, 0x62, + 0x85, 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x00, 0x26, 0x84, 0xc0, 0x03, 0xa9, + 0x25, 0x00, 0x54, 0x80, 0xc0, 0x00, 0xa9, 0x82, 0x00, 0x01, 0x0c, 0xbf, + 0x88, 0xc0, 0x00, 0x42, 0x82, 0x00, 0x00, 0x8f, 0x81, 0xc0, 0x00, 0x28, + 0x82, 0x00, 0x00, 0xa9, 0x80, 0xc0, 0x00, 0x2b, 0x82, 0x00, 0x00, 0xb4, + 0x82, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0x97, 0x81, 0xc0, 0x00, 0x2c, + 0x82, 0x00, 0x00, 0x9c, 0x9a, 0xc0, 0x00, 0x1e, 0x82, 0x00, 0x00, 0x8b, + 0x85, 0xc0, 0x00, 0x51, 0x82, 0x00, 0x01, 0x12, 0xbb, 0x81, 0xc0, 0x05, + 0xb8, 0x70, 0x10, 0x00, 0x03, 0xa9, 0x80, 0xc0, 0x00, 0x7f, 0x82, 0x00, + 0x00, 0x2f, 0x88, 0xc0, 0x01, 0xbf, 0x19, 0x82, 0x00, 0x00, 0xb2, 0x80, + 0xc0, 0x01, 0xbb, 0x05, 0x81, 0x00, 0x01, 0x12, 0xbf, 0x80, 0xc0, 0x00, + 0x0e, 0x82, 0x00, 0x01, 0x7b, 0xbd, 0x81, 0xc0, 0x00, 0x41, 0x82, 0x00, + 0x05, 0x3e, 0xbf, 0xc0, 0xc0, 0xaf, 0x04, 0x81, 0x00, 0x01, 0x06, 0xbc, + 0x99, 0xc0, 0x00, 0xb5, 0x83, 0x00, 0x00, 0xb3, 0x84, 0xc0, 0x01, 0xbf, + 0x16, 0x83, 0x00, 0x05, 0x2e, 0x71, 0x79, 0x63, 0x48, 0x0d, 0x80, 0x00, + 0x00, 0x46, 0x81, 0xc0, 0x00, 0x42, 0x82, 0x00, 0x00, 0x42, 0x88, 0xc0, + 0x00, 0x9f, 0x82, 0x00, 0x01, 0x07, 0xbf, 0x80, 0xc0, 0x00, 0x9b, 0x82, + 0x00, 0x00, 0x3b, 0x81, 0xc0, 0x00, 0x12, 0x83, 0x00, 0x06, 0x0b, 0x21, + 0xb2, 0xc0, 0xc0, 0x97, 0x02, 0x82, 0x00, 0x03, 0x42, 0x97, 0xa7, 0x49, + 0x82, 0x00, 0x00, 0x18, 0x9a, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x1d, + 0x84, 0xc0, 0x01, 0xbd, 0x6c, 0x8d, 0x00, 0x05, 0x9f, 0xc0, 0xc0, 0xbf, + 0x8e, 0x07, 0x82, 0x00, 0x01, 0x13, 0xb6, 0x86, 0xc0, 0x01, 0xb6, 0x40, + 0x83, 0x00, 0x00, 0x91, 0x80, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x64, + 0x81, 0xc0, 0x00, 0x60, 0x82, 0x00, 0x02, 0x2f, 0x7e, 0xbb, 0x81, 0xc0, + 0x01, 0x75, 0x05, 0x8b, 0x00, 0x00, 0x88, 0x99, 0xc0, 0x00, 0x65, 0x82, + 0x00, 0x00, 0x45, 0x84, 0xc0, 0x00, 0x40, 0x8d, 0x00, 0x00, 0x38, 0x80, + 0xc0, 0x00, 0x6d, 0x85, 0x00, 0x00, 0x1a, 0x86, 0xc0, 0x00, 0x13, 0x84, + 0x00, 0x04, 0x02, 0xa1, 0xc0, 0xc0, 0x4e, 0x82, 0x00, 0x00, 0x8e, 0x81, + 0xc0, 0x05, 0xbe, 0x76, 0x29, 0x10, 0x52, 0xa0, 0x85, 0xc0, 0x05, 0xa4, + 0x5a, 0x2b, 0x11, 0x0a, 0x04, 0x87, 0x00, 0x00, 0x92, 0xff, 0xc0, 0xff, + 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, + 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xd6, 0xc0, 0x09, + 0xc5, 0xd4, 0xe2, 0xec, 0xf6, 0xfd, 0xfe, 0xf8, 0xe7, 0xc6, 0x95, 0xc0, + 0x03, 0xce, 0xe7, 0xfa, 0xdd, 0x81, 0xc0, 0x01, 0xd4, 0xca, 0x80, 0xc0, + 0x01, 0xc1, 0xca, 0xd1, 0xc0, 0x01, 0xc2, 0xea, 0x86, 0xff, 0x00, 0xf1, + 0x92, 0xc0, 0x02, 0xcf, 0xdf, 0xef, 0x80, 0xff, 0x0c, 0xf9, 0xc0, 0xc0, + 0xc5, 0xed, 0xff, 0xed, 0xc0, 0xc0, 0xc5, 0xef, 0xfe, 0xcd, 0xd0, 0xc0, + 0x0b, 0xec, 0xff, 0xff, 0xef, 0xdf, 0xd3, 0xc9, 0xc4, 0xc1, 0xc5, 0xda, + 0xfb, 0x91, 0xc0, 0x13, 0xd5, 0xfe, 0xff, 0xff, 0xf9, 0xda, 0xc7, 0xf7, + 0xc0, 0xc7, 0xf6, 0xfa, 0xff, 0xe2, 0xc0, 0xcb, 0xf7, 0xff, 0xfe, 0xce, + 0xcf, 0xc0, 0x0c, 0xd2, 0xfe, 0xf3, 0xe4, 0xc5, 0xc0, 0xcb, 0xe7, 0xca, + 0xc0, 0xc0, 0xd1, 0xdc, 0x8b, 0xc0, 0x02, 0xc5, 0xe6, 0xcb, 0x80, 0xc0, + 0x12, 0xf1, 0xff, 0xfd, 0xe0, 0xc2, 0xc0, 0xd2, 0xe6, 0xc6, 0xf6, 0xd7, + 0xe0, 0xfe, 0xc7, 0xd0, 0xfc, 0xff, 0xff, 0xd6, 0xbc, 0xc0, 0x02, 0xc5, + 0xe6, 0xcb, 0x93, 0xc0, 0x06, 0xcf, 0xf4, 0xd1, 0xd2, 0xde, 0xe6, 0xd5, + 0x8c, 0xc0, 0x01, 0xef, 0xed, 0x81, 0xc0, 0x02, 0xf8, 0xe5, 0xc6, 0x80, + 0xc0, 0x0b, 0xef, 0xd1, 0xf3, 0xd8, 0xc4, 0xfa, 0xe3, 0xcf, 0xfc, 0xe6, + 0xfc, 0xdf, 0xbd, 0xc0, 0x01, 0xef, 0xed, 0x93, 0xc0, 0x05, 0xc9, 0xfb, + 0xf8, 0xef, 0xe1, 0xcf, 0x8b, 0xc0, 0x05, 0xdf, 0xfa, 0xff, 0xff, 0xf9, + 0xc5, 0x85, 0xc0, 0x0b, 0xd4, 0xf3, 0xeb, 0xe0, 0xc0, 0xe7, 0xfb, 0xd0, + 0xfb, 0xda, 0xea, 0xec, 0xbb, 0xc0, 0x05, 0xdf, 0xfa, 0xff, 0xff, 0xf9, + 0xc5, 0x8f, 0xc0, 0x06, 0xcc, 0xf4, 0xfa, 0xfe, 0xe8, 0xcd, 0xc2, 0x82, + 0xc0, 0x0f, 0xcf, 0xef, 0xfd, 0xde, 0xc0, 0xc0, 0xcf, 0xef, 0xfd, 0xde, + 0xd6, 0xfb, 0xfd, 0xff, 0xff, 0xd8, 0x85, 0xc0, 0x0c, 0xc3, 0xf8, 0xf7, + 0xec, 0xc0, 0xd0, 0xff, 0xe4, 0xf8, 0xd8, 0xdd, 0xfa, 0xc5, 0x80, 0xc0, + 0x0b, 0xce, 0xea, 0xfb, 0xd7, 0xc0, 0xc0, 0xc3, 0xda, 0xc1, 0xc0, 0xde, + 0xf3, 0x80, 0xc0, 0x03, 0xce, 0xea, 0xfb, 0xd7, 0x80, 0xc0, 0x03, 0xc1, + 0xd8, 0xf3, 0xf2, 0x81, 0xc0, 0x03, 0xc7, 0xe7, 0xfb, 0xf4, 0x89, 0xc0, + 0x11, 0xc7, 0xe7, 0xfb, 0xf4, 0xc0, 0xc0, 0xc3, 0xda, 0xc1, 0xc0, 0xde, + 0xf3, 0xd6, 0xfb, 0xfd, 0xff, 0xff, 0xd8, 0x91, 0xc0, 0x00, 0xd2, 0x81, + 0xff, 0x14, 0xfe, 0xee, 0xd7, 0xc1, 0xc0, 0xda, 0xfe, 0xf3, 0xe3, 0xf5, + 0xc0, 0xda, 0xfe, 0xf3, 0xe3, 0xf5, 0xc2, 0xc7, 0xf8, 0xd3, 0xc4, 0x86, + 0xc0, 0x4e, 0xe5, 0xff, 0xf8, 0xc4, 0xc4, 0xf7, 0xfb, 0xf6, 0xda, 0xce, + 0xfe, 0xd8, 0xc0, 0xc0, 0xc3, 0xe8, 0xf8, 0xdf, 0xfa, 0xc9, 0xc0, 0xc0, + 0xec, 0xe9, 0xc1, 0xe7, 0xff, 0xef, 0xc0, 0xc3, 0xe8, 0xf8, 0xdf, 0xfa, + 0xc9, 0xc0, 0xc0, 0xc6, 0xf0, 0xff, 0xf2, 0xdc, 0xf6, 0xc0, 0xc0, 0xd2, + 0xfb, 0xe5, 0xd4, 0xec, 0xc0, 0xc4, 0xe0, 0xe0, 0xc2, 0xe4, 0xfa, 0xcb, + 0xc0, 0xcf, 0xe1, 0xd2, 0xfb, 0xe5, 0xd4, 0xec, 0xc0, 0xc0, 0xec, 0xe9, + 0xc1, 0xe7, 0xff, 0xef, 0xc2, 0xc7, 0xf8, 0xd3, 0xc4, 0x91, 0xc0, 0x18, + 0xc3, 0xf8, 0xfb, 0xce, 0xc6, 0xcf, 0xdb, 0xf0, 0xff, 0xea, 0xd2, 0xff, + 0xe3, 0xc1, 0xec, 0xfc, 0xd2, 0xff, 0xe3, 0xc1, 0xec, 0xfc, 0xc6, 0xf5, + 0xea, 0x87, 0xc0, 0x4d, 0xd1, 0xff, 0xfe, 0xd0, 0xc0, 0xe9, 0xff, 0xff, + 0xde, 0xc1, 0xf5, 0xf5, 0xc0, 0xc0, 0xc6, 0xf3, 0xdf, 0xc2, 0xec, 0xfa, + 0xc7, 0xc0, 0xd4, 0xf9, 0xc4, 0xe7, 0xf0, 0xfd, 0xc8, 0xc6, 0xf3, 0xdf, + 0xc2, 0xec, 0xfa, 0xc7, 0xc0, 0xc5, 0xf6, 0xfb, 0xd9, 0xc6, 0xfa, 0xf2, + 0xc0, 0xcf, 0xfe, 0xe1, 0xd5, 0xe2, 0xc3, 0xc9, 0xf7, 0xf8, 0xd6, 0xf2, + 0xff, 0xfc, 0xc4, 0xd5, 0xfe, 0xff, 0xfe, 0xe1, 0xd5, 0xe2, 0xc3, 0xc0, + 0xd4, 0xf9, 0xc4, 0xe7, 0xf0, 0xfd, 0xc8, 0xc6, 0xf5, 0xea, 0x93, 0xc0, + 0x02, 0xe2, 0xff, 0xd0, 0x81, 0xc0, 0x14, 0xca, 0xff, 0xfb, 0xf4, 0xe5, + 0xc0, 0xc0, 0xf9, 0xee, 0xf4, 0xe5, 0xc0, 0xc0, 0xf9, 0xf5, 0xeb, 0xff, + 0xcd, 0xc0, 0xcb, 0xc4, 0x83, 0xc0, 0x51, 0xc4, 0xf8, 0xff, 0xe3, 0xc0, + 0xd8, 0xff, 0xff, 0xe4, 0xc0, 0xd9, 0xff, 0xda, 0xc0, 0xc0, 0xee, 0xd6, + 0xc0, 0xe3, 0xfd, 0xd1, 0xc0, 0xca, 0xf3, 0xd9, 0xde, 0xe5, 0xf6, 0xe3, + 0xc0, 0xee, 0xd6, 0xc0, 0xe3, 0xfd, 0xd1, 0xc0, 0xca, 0xe9, 0xfa, 0xca, + 0xc0, 0xee, 0xff, 0xdc, 0xc0, 0xf1, 0xff, 0xe0, 0xca, 0xc0, 0xd4, 0xef, + 0xf1, 0xcb, 0xf6, 0xd9, 0xf2, 0xde, 0xda, 0xef, 0xfa, 0xfc, 0xff, 0xe0, + 0xca, 0xc0, 0xd4, 0xc4, 0xf3, 0xd9, 0xde, 0xe5, 0xf6, 0xe3, 0xc7, 0xeb, + 0xff, 0xcd, 0xc0, 0xcb, 0xc4, 0x90, 0xc0, 0x1b, 0xf9, 0xff, 0xd7, 0xc2, + 0xc3, 0xcd, 0xe0, 0xfb, 0xff, 0xdb, 0xfd, 0xcb, 0xc0, 0xc0, 0xfc, 0xdf, + 0xff, 0xcb, 0xc0, 0xc0, 0xfc, 0xdf, 0xff, 0xff, 0xc8, 0xda, 0xeb, 0xc1, + 0x83, 0xc0, 0x51, 0xea, 0xff, 0xf6, 0xc2, 0xc4, 0xfc, 0xff, 0xec, 0xc0, + 0xc0, 0xf0, 0xff, 0xc7, 0xc0, 0xc2, 0xff, 0xd2, 0xe7, 0xed, 0xf2, 0xd6, + 0xe3, 0xe0, 0xfe, 0xd7, 0xed, 0xdd, 0xff, 0xc9, 0xca, 0xff, 0xc9, 0xe7, + 0xed, 0xf2, 0xd6, 0xe3, 0xe0, 0xfc, 0xd3, 0xc0, 0xe5, 0xfb, 0xfd, 0xc4, + 0xc7, 0xfd, 0xff, 0xcd, 0xc7, 0xe4, 0xe8, 0xfb, 0xd4, 0xf8, 0xd7, 0xce, + 0xf4, 0xe2, 0xd7, 0xfd, 0xcf, 0xfd, 0xff, 0xcd, 0xc7, 0xe4, 0xe8, 0xc0, + 0xfe, 0xd7, 0xed, 0xdd, 0xff, 0xc9, 0xcb, 0xfc, 0xff, 0xc8, 0xda, 0xeb, + 0xc1, 0x90, 0xc0, 0x00, 0xf6, 0x83, 0xff, 0x0e, 0xf7, 0xd4, 0xc0, 0xef, + 0xcb, 0xc5, 0xde, 0xf3, 0xe3, 0xf4, 0xcb, 0xc5, 0xde, 0xf3, 0xe3, 0x80, + 0xff, 0x01, 0xec, 0xc2, 0x84, 0xc0, 0x2e, 0xf8, 0xff, 0xd0, 0xc0, 0xd0, + 0xff, 0xf2, 0xc2, 0xc0, 0xc0, 0xfc, 0xff, 0xc9, 0xd1, 0xf4, 0xff, 0xff, + 0xf8, 0xc5, 0xfb, 0xff, 0xea, 0xc0, 0xfa, 0xfb, 0xc6, 0xf6, 0xff, 0xdc, + 0xec, 0xf8, 0xff, 0xf8, 0xc5, 0xfb, 0xff, 0xea, 0xc0, 0xf6, 0xc8, 0xe5, + 0xf3, 0xe5, 0xe9, 0xe1, 0xd5, 0xf6, 0x80, 0xff, 0x0b, 0xec, 0xc2, 0xfb, + 0xff, 0xdc, 0xc0, 0xec, 0xf6, 0xd1, 0xea, 0xff, 0xd9, 0x81, 0xff, 0x09, + 0xec, 0xc2, 0xc0, 0xfa, 0xfb, 0xc6, 0xf6, 0xff, 0xdc, 0xec, 0x80, 0xff, + 0x01, 0xec, 0xc2, 0x91, 0xc0, 0x06, 0xcb, 0xed, 0xfb, 0xfe, 0xf7, 0xe8, + 0xd2, 0x80, 0xc0, 0x0e, 0xc9, 0xf3, 0xfc, 0xe5, 0xc3, 0xc0, 0xc9, 0xf3, + 0xfc, 0xe5, 0xc3, 0xc0, 0xed, 0xf9, 0xdd, 0x86, 0xc0, 0x06, 0xe3, 0xe9, + 0xc0, 0xc0, 0xc6, 0xf4, 0xc6, 0x80, 0xc0, 0x44, 0xfa, 0xff, 0xff, 0xfa, + 0xcf, 0xd3, 0xf7, 0xcb, 0xc0, 0xfd, 0xeb, 0xc1, 0xc0, 0xe7, 0xd6, 0xc0, + 0xfd, 0xff, 0xe7, 0xc2, 0xd3, 0xf7, 0xcb, 0xc0, 0xfd, 0xeb, 0xc1, 0xc0, + 0xd8, 0xfb, 0xe3, 0xc6, 0xfb, 0xf2, 0xca, 0xc0, 0xd3, 0xf9, 0xf8, 0xdf, + 0xc1, 0xc0, 0xe3, 0xe7, 0xc0, 0xc0, 0xfb, 0xd8, 0xc0, 0xfb, 0xff, 0xeb, + 0xd9, 0xf9, 0xf8, 0xdf, 0xc1, 0xc0, 0xc0, 0xe7, 0xd6, 0xc0, 0xfd, 0xff, + 0xe7, 0xc2, 0xed, 0xf9, 0xdd, 0xb5, 0xc0, 0x01, 0xc1, 0xc1, 0x85, 0xc0, + 0x03, 0xdb, 0xfb, 0xea, 0xc7, 0x82, 0xc0, 0x00, 0xcb, 0x83, 0xc0, 0x01, + 0xd3, 0xcf, 0x83, 0xc0, 0x00, 0xcb, 0x82, 0xc0, 0x03, 0xc1, 0xe9, 0xe8, + 0xc2, 0x89, 0xc0, 0x04, 0xc2, 0xc0, 0xc0, 0xcf, 0xcc, 0x88, 0xc0, 0x01, + 0xd3, 0xcf, 0xe1, 0xc0, 0x03, 0xc4, 0xf0, 0xf5, 0xc1, 0xff, 0xc0, 0x03, + 0xc1, 0xf1, 0xfe, 0xcd, 0xff, 0xc0, 0x03, 0xc0, 0xde, 0xff, 0xd8, 0xff, + 0xc0, 0x03, 0xc0, 0xc0, 0xef, 0xd7, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0, 0xc8, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x8e, 0xc0, + 0x08, 0xb2, 0x98, 0x83, 0x6e, 0x5a, 0x45, 0x30, 0x1b, 0x39, 0xa8, 0xc0, + 0x00, 0x26, 0x8c, 0x00, 0x00, 0x49, 0x81, 0xc0, 0x00, 0x53, 0x8c, 0x00, + 0x03, 0x0d, 0xc0, 0xa1, 0x02, 0x84, 0x00, 0x00, 0x13, 0x9f, 0xc0, 0x01, + 0x6e, 0x0b, 0x83, 0x00, 0x00, 0x5a, 0xa8, 0xc0, 0x01, 0xb9, 0x1d, 0x8b, + 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0xbf, 0x45, 0x8b, 0x00, 0x03, 0x04, + 0xc0, 0xc0, 0x90, 0x83, 0x00, 0x01, 0x41, 0xb5, 0xa0, 0xc0, 0x01, 0xb9, + 0x15, 0x82, 0x00, 0x00, 0x82, 0xa9, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x09, + 0x11, 0x80, 0xa6, 0xa6, 0x91, 0x70, 0x22, 0x00, 0x00, 0x38, 0x82, 0xc0, + 0x00, 0x7b, 0x82, 0x00, 0x0d, 0x0b, 0x75, 0xa0, 0xab, 0x9a, 0x82, 0x41, + 0x04, 0x00, 0x00, 0xbb, 0xc0, 0xbe, 0x07, 0x82, 0x00, 0x00, 0xa3, 0xa2, + 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00, 0xaa, 0xa9, 0xc0, 0x00, 0x38, 0x82, + 0x00, 0x00, 0x73, 0x82, 0xc0, 0x03, 0xbf, 0x66, 0x00, 0x2f, 0x82, 0xc0, + 0x00, 0x65, 0x82, 0x00, 0x00, 0x56, 0x83, 0xc0, 0x05, 0x9d, 0x11, 0x00, + 0xb2, 0xc0, 0xb2, 0x82, 0x00, 0x00, 0x1d, 0xa2, 0xc0, 0x00, 0xad, 0x82, + 0x00, 0x01, 0x11, 0xbf, 0xa9, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0xac, + 0x80, 0xc0, 0x05, 0xb4, 0x04, 0xc0, 0xc0, 0x48, 0x26, 0x82, 0xc0, 0x00, + 0x40, 0x82, 0x00, 0x00, 0x84, 0x80, 0xc0, 0x08, 0xb1, 0x0b, 0xc0, 0xc0, + 0x91, 0x00, 0xa9, 0xc0, 0x8e, 0x82, 0x00, 0x00, 0x47, 0xa2, 0xc0, 0x00, + 0x85, 0x82, 0x00, 0x00, 0x3a, 0x98, 0xc0, 0x11, 0xb3, 0x95, 0x7a, 0x60, + 0x45, 0x2a, 0x0f, 0x66, 0xc0, 0xc0, 0xa4, 0x58, 0x20, 0x0b, 0x69, 0xc0, + 0xc0, 0xac, 0x82, 0x00, 0x00, 0x1a, 0x80, 0xc0, 0x06, 0xb2, 0x46, 0x00, + 0xc0, 0xc0, 0x97, 0x1d, 0x82, 0xc0, 0x00, 0x18, 0x82, 0x00, 0x0c, 0xb0, + 0xc0, 0xc0, 0xb7, 0x54, 0x00, 0xc0, 0xc0, 0xbf, 0x3d, 0xa6, 0xc0, 0x67, + 0x82, 0x00, 0x14, 0x6d, 0xc0, 0xc0, 0xaf, 0x91, 0x77, 0x5d, 0x42, 0x28, + 0x0e, 0x91, 0xc0, 0xc0, 0xb4, 0x70, 0x34, 0x15, 0x05, 0x17, 0x53, 0xb5, + 0x87, 0xc0, 0x04, 0x9d, 0x60, 0x2e, 0x16, 0x08, 0x85, 0x00, 0x00, 0x63, + 0x98, 0xc0, 0x00, 0x68, 0x83, 0x00, 0x0a, 0x16, 0xc0, 0x6f, 0x05, 0x00, + 0x00, 0x09, 0xb5, 0xc0, 0xc0, 0x85, 0x82, 0x00, 0x0a, 0x08, 0x1d, 0x1d, + 0x14, 0x02, 0x00, 0x00, 0xc0, 0xc0, 0xbf, 0xa6, 0x81, 0xc0, 0x00, 0xb1, + 0x82, 0x00, 0x06, 0x01, 0x1d, 0x1d, 0x15, 0x04, 0x00, 0x00, 0x83, 0xc0, + 0x00, 0x41, 0x82, 0x00, 0x03, 0x93, 0xc0, 0xc0, 0x51, 0x83, 0x00, 0x03, + 0x5d, 0xbe, 0x6d, 0x0e, 0x83, 0x00, 0x00, 0x4a, 0x85, 0xc0, 0x01, 0xa7, + 0x3c, 0x8a, 0x00, 0x00, 0x8b, 0x99, 0xc0, 0x00, 0x87, 0x82, 0x00, 0x01, + 0x05, 0x6e, 0x81, 0x00, 0x00, 0x54, 0x80, 0xc0, 0x00, 0x5e, 0x89, 0x00, + 0x85, 0xc0, 0x00, 0x8a, 0x89, 0x00, 0x83, 0xc0, 0x00, 0x1a, 0x81, 0x00, + 0x01, 0x01, 0xb7, 0x80, 0xc0, 0x00, 0x68, 0x82, 0x00, 0x01, 0x42, 0x39, + 0x85, 0x00, 0x00, 0x0f, 0x84, 0xc0, 0x01, 0x8f, 0x0e, 0x84, 0x00, 0x01, + 0x12, 0x02, 0x82, 0x00, 0x00, 0xb2, 0x99, 0xc0, 0x00, 0xb8, 0x82, 0x00, + 0x06, 0x02, 0x02, 0x0e, 0x31, 0x14, 0x02, 0xa7, 0x80, 0xc0, 0x00, 0x36, + 0x89, 0x00, 0x85, 0xc0, 0x00, 0x63, 0x89, 0x00, 0x82, 0xc0, 0x00, 0xb4, + 0x82, 0x00, 0x00, 0x1f, 0x81, 0xc0, 0x00, 0x8b, 0x84, 0x00, 0x02, 0x2c, + 0x62, 0x3a, 0x82, 0x00, 0x00, 0x12, 0x83, 0xc0, 0x01, 0x99, 0x06, 0x82, + 0x00, 0x04, 0x1b, 0x84, 0xb2, 0xb5, 0x01, 0x81, 0x00, 0x00, 0x1a, 0x9a, + 0xc0, 0x00, 0xa2, 0x83, 0x00, 0x04, 0x38, 0xb8, 0xc0, 0xbd, 0x8a, 0x80, + 0xc0, 0x01, 0xbf, 0x0f, 0x82, 0x00, 0x06, 0x91, 0xb5, 0xb6, 0x9e, 0x58, + 0x02, 0x00, 0x85, 0xc0, 0x00, 0x3b, 0x82, 0x00, 0x06, 0x6d, 0xb3, 0xb8, + 0x9f, 0x54, 0x00, 0x00, 0x82, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x45, + 0x81, 0xc0, 0x00, 0x72, 0x83, 0x00, 0x03, 0x4c, 0xbe, 0xc0, 0xb2, 0x82, + 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, 0xb2, 0x14, 0x82, 0x00, 0x04, 0x4e, + 0xba, 0xc0, 0xc0, 0x8d, 0x82, 0x00, 0x00, 0x42, 0x9a, 0xc0, 0x00, 0x7b, + 0x82, 0x00, 0x01, 0x07, 0xaf, 0x84, 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x01, + 0x0d, 0xbf, 0x81, 0xc0, 0x01, 0x6c, 0x00, 0x85, 0xc0, 0x00, 0x14, 0x82, + 0x00, 0x00, 0xa3, 0x81, 0xc0, 0x01, 0x57, 0x00, 0x82, 0xc0, 0x00, 0x68, + 0x82, 0x00, 0x00, 0x6b, 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x04, 0x16, + 0xbb, 0xc0, 0xc0, 0xa7, 0x82, 0x00, 0x00, 0x59, 0x82, 0xc0, 0x00, 0x54, + 0x82, 0x00, 0x01, 0x3b, 0xbe, 0x80, 0xc0, 0x00, 0x63, 0x82, 0x00, 0x00, + 0x6b, 0x9a, 0xc0, 0x00, 0x52, 0x82, 0x00, 0x00, 0x45, 0x85, 0xc0, 0x00, + 0x81, 0x82, 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, 0xb6, 0x04, 0x84, 0xc0, + 0x00, 0xac, 0x82, 0x00, 0x01, 0x0b, 0xbe, 0x81, 0xc0, 0x01, 0xa2, 0x00, + 0x82, 0xc0, 0x00, 0x42, 0x82, 0x00, 0x00, 0x91, 0x81, 0xc0, 0x00, 0x28, + 0x82, 0x00, 0x00, 0x6f, 0x80, 0xc0, 0x00, 0x78, 0x82, 0x00, 0x00, 0x8a, + 0x81, 0xc0, 0x01, 0xab, 0x04, 0x81, 0x00, 0x01, 0x08, 0xac, 0x81, 0xc0, + 0x00, 0x3a, 0x82, 0x00, 0x00, 0x93, 0x9a, 0xc0, 0x00, 0x29, 0x82, 0x00, + 0x00, 0x79, 0x85, 0xc0, 0x00, 0x59, 0x82, 0x00, 0x00, 0x5f, 0x83, 0xc0, + 0x00, 0xbd, 0x84, 0xc0, 0x00, 0x85, 0x82, 0x00, 0x00, 0x31, 0x82, 0xc0, + 0x01, 0xbf, 0xa8, 0x82, 0xc0, 0x00, 0x1a, 0x82, 0x00, 0x00, 0xb5, 0x80, + 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xaf, 0x80, 0xc0, 0x00, 0x40, + 0x81, 0x00, 0x01, 0x04, 0xb8, 0x81, 0xc0, 0x00, 0x6b, 0x82, 0x00, 0x00, + 0x51, 0x81, 0xc0, 0x01, 0xbf, 0x11, 0x81, 0x00, 0x01, 0x02, 0xb8, 0x99, + 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xa8, 0x85, 0xc0, 0x00, 0x32, + 0x82, 0x00, 0x00, 0x88, 0x86, 0xc0, 0x01, 0xa3, 0x4a, 0x80, 0xc0, 0x00, + 0x5e, 0x82, 0x00, 0x00, 0x57, 0x88, 0xc0, 0x00, 0xb4, 0x82, 0x00, 0x00, + 0x1d, 0x81, 0xc0, 0x00, 0x9b, 0x82, 0x00, 0x00, 0x25, 0x80, 0xc0, 0x01, + 0xbc, 0x0b, 0x81, 0x00, 0x00, 0x2f, 0x82, 0xc0, 0x00, 0x31, 0x82, 0x00, + 0x00, 0x8f, 0x81, 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x00, 0x23, 0x9a, 0xc0, + 0x00, 0x99, 0x82, 0x00, 0x01, 0x10, 0xbf, 0x84, 0xc0, 0x01, 0xbe, 0x0b, + 0x82, 0x00, 0x00, 0xaf, 0x85, 0xc0, 0x02, 0xb3, 0x1d, 0x60, 0x80, 0xc0, + 0x00, 0x36, 0x82, 0x00, 0x00, 0x7f, 0x88, 0xc0, 0x00, 0x8e, 0x82, 0x00, + 0x00, 0x43, 0x81, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x57, 0x80, 0xc0, + 0x00, 0x91, 0x82, 0x00, 0x00, 0x62, 0x82, 0xc0, 0x00, 0x15, 0x82, 0x00, + 0x00, 0xaf, 0x81, 0xc0, 0x00, 0x7f, 0x82, 0x00, 0x00, 0x4b, 0x9a, 0xc0, + 0x00, 0x6f, 0x82, 0x00, 0x00, 0x39, 0x85, 0xc0, 0x00, 0xa3, 0x82, 0x00, + 0x01, 0x0c, 0xbf, 0x84, 0xc0, 0x07, 0xb8, 0x33, 0x08, 0xb2, 0xc0, 0xc0, + 0xbf, 0x0f, 0x82, 0x00, 0x00, 0xa6, 0x88, 0xc0, 0x00, 0x68, 0x82, 0x00, + 0x00, 0x69, 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x00, 0x81, 0x80, 0xc0, + 0x00, 0x5a, 0x82, 0x00, 0x00, 0x8f, 0x82, 0xc0, 0x00, 0x05, 0x82, 0x00, + 0x00, 0xb7, 0x81, 0xc0, 0x00, 0x55, 0x82, 0x00, 0x00, 0x73, 0x9a, 0xc0, + 0x00, 0x47, 0x82, 0x00, 0x00, 0x62, 0x85, 0xc0, 0x00, 0x7b, 0x82, 0x00, + 0x00, 0x26, 0x84, 0xc0, 0x03, 0xa9, 0x25, 0x00, 0x54, 0x80, 0xc0, 0x00, + 0xa9, 0x82, 0x00, 0x01, 0x0c, 0xbf, 0x88, 0xc0, 0x00, 0x42, 0x82, 0x00, + 0x00, 0x8f, 0x81, 0xc0, 0x00, 0x28, 0x82, 0x00, 0x00, 0xa9, 0x80, 0xc0, + 0x00, 0x2b, 0x82, 0x00, 0x00, 0xb4, 0x82, 0xc0, 0x00, 0x14, 0x82, 0x00, + 0x00, 0x97, 0x81, 0xc0, 0x00, 0x2c, 0x82, 0x00, 0x00, 0x9c, 0x9a, 0xc0, + 0x00, 0x1e, 0x82, 0x00, 0x00, 0x8b, 0x85, 0xc0, 0x00, 0x51, 0x82, 0x00, + 0x01, 0x12, 0xbb, 0x81, 0xc0, 0x05, 0xb8, 0x70, 0x10, 0x00, 0x03, 0xa9, + 0x80, 0xc0, 0x00, 0x7f, 0x82, 0x00, 0x00, 0x2f, 0x88, 0xc0, 0x01, 0xbf, + 0x19, 0x82, 0x00, 0x00, 0xb2, 0x80, 0xc0, 0x01, 0xbb, 0x05, 0x81, 0x00, + 0x01, 0x12, 0xbf, 0x80, 0xc0, 0x00, 0x0e, 0x82, 0x00, 0x01, 0x7b, 0xbd, + 0x81, 0xc0, 0x00, 0x41, 0x82, 0x00, 0x05, 0x3e, 0xbf, 0xc0, 0xc0, 0xaf, + 0x04, 0x81, 0x00, 0x01, 0x06, 0xbc, 0x99, 0xc0, 0x00, 0xb5, 0x83, 0x00, + 0x00, 0xb3, 0x84, 0xc0, 0x01, 0xbf, 0x16, 0x83, 0x00, 0x05, 0x2e, 0x71, + 0x79, 0x63, 0x48, 0x0d, 0x80, 0x00, 0x00, 0x46, 0x81, 0xc0, 0x00, 0x42, + 0x82, 0x00, 0x00, 0x42, 0x88, 0xc0, 0x00, 0x9f, 0x82, 0x00, 0x01, 0x07, + 0xbf, 0x80, 0xc0, 0x00, 0x9b, 0x82, 0x00, 0x00, 0x3b, 0x81, 0xc0, 0x00, + 0x12, 0x83, 0x00, 0x06, 0x0b, 0x21, 0xb2, 0xc0, 0xc0, 0x97, 0x02, 0x82, + 0x00, 0x03, 0x42, 0x97, 0xa7, 0x49, 0x82, 0x00, 0x00, 0x18, 0x9a, 0xc0, + 0x00, 0x8e, 0x82, 0x00, 0x00, 0x1d, 0x84, 0xc0, 0x01, 0xbd, 0x6c, 0x8d, + 0x00, 0x05, 0x9f, 0xc0, 0xc0, 0xbf, 0x8e, 0x07, 0x82, 0x00, 0x01, 0x13, + 0xb6, 0x86, 0xc0, 0x01, 0xb6, 0x40, 0x83, 0x00, 0x00, 0x91, 0x80, 0xc0, + 0x00, 0x75, 0x82, 0x00, 0x00, 0x64, 0x81, 0xc0, 0x00, 0x60, 0x82, 0x00, + 0x02, 0x2f, 0x7e, 0xbb, 0x81, 0xc0, 0x01, 0x75, 0x05, 0x8b, 0x00, 0x00, + 0x88, 0x99, 0xc0, 0x00, 0x65, 0x82, 0x00, 0x00, 0x45, 0x84, 0xc0, 0x00, + 0x40, 0x8d, 0x00, 0x00, 0x38, 0x80, 0xc0, 0x00, 0x6d, 0x85, 0x00, 0x00, + 0x1a, 0x86, 0xc0, 0x00, 0x13, 0x84, 0x00, 0x04, 0x02, 0xa1, 0xc0, 0xc0, + 0x4e, 0x82, 0x00, 0x00, 0x8e, 0x81, 0xc0, 0x05, 0xbe, 0x76, 0x29, 0x10, + 0x52, 0xa0, 0x85, 0xc0, 0x05, 0xa4, 0x5a, 0x2b, 0x11, 0x0a, 0x04, 0x87, + 0x00, 0x00, 0x92, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, + 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, + 0xc0, 0xff, 0xc0, 0xd6, 0xc0, 0x09, 0xb1, 0x85, 0x5a, 0x38, 0x1b, 0x08, + 0x05, 0x16, 0x4b, 0xad, 0x95, 0xc0, 0x03, 0x97, 0x49, 0x10, 0x68, 0x81, + 0xc0, 0x01, 0x83, 0xa0, 0x80, 0xc0, 0x01, 0xbe, 0xa1, 0xd1, 0xc0, 0x02, + 0xb8, 0x41, 0x01, 0x85, 0x00, 0x00, 0x29, 0x92, 0xc0, 0x02, 0x93, 0x60, + 0x2f, 0x80, 0x00, 0x0c, 0x13, 0xc0, 0xc0, 0xb0, 0x35, 0x00, 0x36, 0xc0, + 0xc0, 0xb2, 0x2f, 0x03, 0x99, 0xd0, 0xc0, 0x0b, 0x3a, 0x00, 0x01, 0x2f, + 0x60, 0x85, 0xa3, 0xb4, 0xbd, 0xb0, 0x72, 0x0e, 0x91, 0xc0, 0x13, 0x7f, + 0x02, 0x00, 0x00, 0x14, 0x72, 0xab, 0x18, 0xc0, 0xaa, 0x1b, 0x10, 0x00, + 0x58, 0xc0, 0x9d, 0x1a, 0x00, 0x04, 0x97, 0xcf, 0xc0, 0x0c, 0x89, 0x05, + 0x26, 0x53, 0xaf, 0xc0, 0x9f, 0x48, 0xa3, 0xc0, 0xc0, 0x8c, 0x6b, 0x8b, + 0xc0, 0x02, 0xaf, 0x4b, 0x9f, 0x80, 0xc0, 0x12, 0x2a, 0x00, 0x08, 0x60, + 0xb8, 0xc0, 0x89, 0x4d, 0xad, 0x1d, 0x7a, 0x5f, 0x05, 0xab, 0x90, 0x09, + 0x00, 0x01, 0x7c, 0xbc, 0xc0, 0x02, 0xaf, 0x4b, 0x9f, 0x8e, 0xc0, 0x01, + 0xbf, 0xbe, 0x80, 0xc0, 0x06, 0x91, 0x22, 0x8c, 0x8a, 0x65, 0x4b, 0x82, + 0x8c, 0xc0, 0x02, 0x31, 0x38, 0xbf, 0x80, 0xc0, 0x02, 0x14, 0x50, 0xac, + 0x80, 0xc0, 0x0b, 0x2f, 0x8e, 0x25, 0x78, 0xb2, 0x0f, 0x54, 0x94, 0x08, + 0x4b, 0x08, 0x61, 0xbd, 0xc0, 0x02, 0x31, 0x38, 0xbf, 0x92, 0xc0, 0x06, + 0xa3, 0x0e, 0x14, 0x32, 0x5b, 0x91, 0xbf, 0x8a, 0xc0, 0x05, 0x60, 0x0e, + 0x01, 0x00, 0x13, 0xb1, 0x85, 0xc0, 0x0b, 0x85, 0x24, 0x3d, 0x5e, 0xc0, + 0x49, 0x0c, 0x8f, 0x0e, 0x6f, 0x41, 0x38, 0xbb, 0xc0, 0x05, 0x60, 0x0e, + 0x01, 0x00, 0x13, 0xb1, 0x8f, 0xc0, 0x06, 0x9b, 0x23, 0x11, 0x02, 0x48, + 0x98, 0xba, 0x82, 0xc0, 0x0f, 0x94, 0x30, 0x08, 0x64, 0xc0, 0xc0, 0x94, + 0x30, 0x08, 0x64, 0x7d, 0x0b, 0x06, 0x00, 0x00, 0x75, 0x85, 0xc0, 0x0c, + 0xb6, 0x15, 0x19, 0x38, 0xbf, 0x8f, 0x01, 0x51, 0x14, 0x75, 0x66, 0x10, + 0xb0, 0x80, 0xc0, 0x0b, 0x96, 0x40, 0x0d, 0x7b, 0xc0, 0xc0, 0xb6, 0x70, + 0xbe, 0xc0, 0x65, 0x25, 0x80, 0xc0, 0x03, 0x96, 0x40, 0x0d, 0x7b, 0x80, + 0xc0, 0x03, 0xbe, 0x77, 0x23, 0x28, 0x81, 0xc0, 0x03, 0xa9, 0x4a, 0x0d, + 0x23, 0x89, 0xc0, 0x11, 0xa9, 0x4a, 0x0d, 0x23, 0xc0, 0xc0, 0xb6, 0x70, + 0xbe, 0xc0, 0x65, 0x25, 0x7d, 0x0b, 0x06, 0x00, 0x00, 0x75, 0x91, 0xc0, + 0x01, 0x8b, 0x01, 0x80, 0x00, 0x14, 0x05, 0x32, 0x7a, 0xbe, 0xc0, 0x70, + 0x02, 0x25, 0x57, 0x1d, 0xc0, 0x70, 0x02, 0x25, 0x57, 0x1d, 0xbb, 0xac, + 0x15, 0x86, 0xb5, 0x86, 0xc0, 0x4e, 0x51, 0x00, 0x15, 0xb2, 0xb5, 0x17, + 0x0d, 0x1a, 0x71, 0x94, 0x02, 0x77, 0xc0, 0xc0, 0xb7, 0x47, 0x15, 0x60, + 0x11, 0xa5, 0xc0, 0xc0, 0x38, 0x44, 0xbc, 0x48, 0x00, 0x30, 0xc0, 0xb7, + 0x47, 0x15, 0x60, 0x11, 0xa5, 0xc0, 0xc0, 0xae, 0x2f, 0x00, 0x27, 0x69, + 0x1b, 0xc0, 0xc0, 0x8b, 0x0b, 0x50, 0x85, 0x39, 0xc0, 0xb3, 0x5e, 0x5d, + 0xba, 0x53, 0x0e, 0x9f, 0xc0, 0x91, 0x5a, 0x8b, 0x0b, 0x50, 0x85, 0x39, + 0xc0, 0xc0, 0x38, 0x44, 0xbc, 0x48, 0x00, 0x30, 0xbb, 0xac, 0x15, 0x86, + 0xb5, 0x91, 0xc0, 0x18, 0xb6, 0x17, 0x0c, 0x96, 0xad, 0x91, 0x6d, 0x2d, + 0x00, 0x3f, 0x88, 0x01, 0x54, 0xbd, 0x3a, 0x09, 0x88, 0x01, 0x54, 0xbd, + 0x3a, 0x09, 0xae, 0x1f, 0x3f, 0x87, 0xc0, 0x4d, 0x8e, 0x01, 0x02, 0x91, + 0xc0, 0x42, 0x00, 0x00, 0x63, 0xbc, 0x1e, 0x1f, 0xbe, 0xc0, 0xae, 0x23, + 0x60, 0xb8, 0x3a, 0x0f, 0xab, 0xc0, 0x82, 0x12, 0xb4, 0x48, 0x2f, 0x06, + 0xa6, 0xae, 0x23, 0x60, 0xb8, 0x3a, 0x0f, 0xab, 0xc0, 0xb0, 0x1c, 0x0c, + 0x73, 0xac, 0x10, 0x26, 0xc0, 0x94, 0x04, 0x5a, 0x7f, 0x5a, 0xb8, 0xa5, + 0x19, 0x17, 0x7e, 0x26, 0x00, 0x0a, 0xb3, 0x7f, 0x05, 0x00, 0x04, 0x5a, + 0x7f, 0x5a, 0xb8, 0xc0, 0x82, 0x12, 0xb4, 0x48, 0x2f, 0x06, 0xa6, 0xae, + 0x1f, 0x3f, 0x93, 0xc0, 0x02, 0x5a, 0x00, 0x90, 0x81, 0xc0, 0x14, 0xa3, + 0x00, 0x0e, 0x23, 0x50, 0xc0, 0xc0, 0x12, 0x32, 0x23, 0x50, 0xc0, 0xc0, + 0x12, 0x1d, 0x3d, 0x00, 0x98, 0xc0, 0x9f, 0xb5, 0x83, 0xc0, 0x51, 0xb2, + 0x15, 0x00, 0x57, 0xc0, 0x77, 0x00, 0x00, 0x51, 0xc0, 0x74, 0x00, 0x72, + 0xc0, 0xc0, 0x33, 0x7b, 0xc0, 0x57, 0x08, 0x8b, 0xc0, 0xa1, 0x25, 0x73, + 0x63, 0x50, 0x1b, 0x56, 0xc0, 0x33, 0x7d, 0xc0, 0x57, 0x08, 0x8b, 0xc0, + 0xa1, 0x42, 0x11, 0xa2, 0xbe, 0x33, 0x00, 0x6c, 0xc0, 0x2a, 0x00, 0x5f, + 0xa1, 0xc0, 0x85, 0x2f, 0x2c, 0x9e, 0x1c, 0x74, 0x29, 0x65, 0x72, 0x32, + 0x10, 0x0b, 0x00, 0x5f, 0xa1, 0xc0, 0x85, 0xb2, 0x25, 0x73, 0x63, 0x50, + 0x1b, 0x56, 0xab, 0x3d, 0x00, 0x98, 0xc0, 0x9f, 0xb5, 0x90, 0xc0, 0x1b, + 0x11, 0x00, 0x79, 0xb9, 0xb8, 0x98, 0x5d, 0x0e, 0x00, 0x6e, 0x06, 0x9d, + 0xc0, 0xc0, 0x09, 0x63, 0x00, 0x9d, 0xc0, 0xc0, 0x09, 0x60, 0x00, 0x00, + 0xa9, 0x71, 0x3d, 0xbc, 0x83, 0xc0, 0x51, 0x3f, 0x00, 0x1b, 0xb9, 0xb2, + 0x0a, 0x00, 0x3b, 0xbe, 0xc0, 0x2c, 0x00, 0xac, 0xc0, 0xb9, 0x00, 0x89, + 0x4a, 0x36, 0x27, 0x7d, 0x55, 0x60, 0x02, 0x7b, 0x35, 0x69, 0x00, 0xa5, + 0xa0, 0x00, 0xa5, 0x4a, 0x36, 0x27, 0x7d, 0x55, 0x60, 0x08, 0x87, 0xc0, + 0x51, 0x0d, 0x08, 0xb3, 0xac, 0x06, 0x00, 0x99, 0xa9, 0x53, 0x45, 0x0b, + 0x84, 0x15, 0x78, 0x95, 0x21, 0x5a, 0x79, 0x07, 0x91, 0x06, 0x00, 0x99, + 0xa9, 0x53, 0x45, 0xc0, 0x02, 0x7b, 0x35, 0x69, 0x00, 0xa5, 0x9e, 0x08, + 0x00, 0xa9, 0x71, 0x3d, 0xbc, 0x90, 0xc0, 0x00, 0x1b, 0x83, 0x00, 0x0e, + 0x17, 0x83, 0xc0, 0x32, 0x9f, 0xb0, 0x63, 0x24, 0x54, 0x22, 0x9f, 0xb0, + 0x63, 0x24, 0x54, 0x80, 0x00, 0x01, 0x3b, 0xb9, 0x84, 0xc0, 0x2e, 0x17, + 0x00, 0x90, 0xc0, 0x91, 0x00, 0x27, 0xb8, 0xc0, 0xc0, 0x08, 0x00, 0xa4, + 0x8d, 0x21, 0x00, 0x00, 0x17, 0xb1, 0x0b, 0x00, 0x3f, 0xbf, 0x0e, 0x0c, + 0xad, 0x1a, 0x00, 0x6a, 0x39, 0x16, 0x00, 0x17, 0xb1, 0x0b, 0x00, 0x3f, + 0xbf, 0x1c, 0xa8, 0x50, 0x23, 0x50, 0x45, 0x5c, 0x81, 0x1b, 0x80, 0x00, + 0x0b, 0x39, 0xbb, 0x0c, 0x00, 0x6a, 0xc0, 0x39, 0x1d, 0x8b, 0x40, 0x00, + 0x73, 0x81, 0x00, 0x09, 0x39, 0xbb, 0xc0, 0x0e, 0x0c, 0xad, 0x1a, 0x00, + 0x6a, 0x39, 0x80, 0x00, 0x01, 0x3b, 0xb9, 0x91, 0xc0, 0x19, 0x9d, 0x37, + 0x0e, 0x04, 0x17, 0x45, 0x8b, 0xbe, 0xc0, 0xc0, 0xa4, 0x23, 0x0a, 0x51, + 0xb8, 0xc0, 0xa4, 0x23, 0x0a, 0x51, 0xb8, 0xc0, 0x37, 0x12, 0x69, 0xbe, + 0x85, 0xc0, 0x06, 0x57, 0x43, 0xc0, 0xc0, 0xaf, 0x23, 0xae, 0x80, 0xc0, + 0x45, 0x0e, 0x00, 0x00, 0x11, 0x93, 0x88, 0x19, 0x9e, 0xc0, 0x05, 0x3b, + 0xbb, 0xc0, 0x49, 0x7d, 0xc0, 0x08, 0x00, 0x4a, 0xbb, 0x88, 0x19, 0x9e, + 0xc0, 0x05, 0x3b, 0xbb, 0xc0, 0x77, 0x0c, 0x57, 0xae, 0x0d, 0x29, 0xa3, + 0xc0, 0x85, 0x11, 0x14, 0x63, 0xbd, 0xc0, 0x55, 0x48, 0xc0, 0xc0, 0x0c, + 0x75, 0xc0, 0x0c, 0x00, 0x3d, 0x73, 0x11, 0x14, 0x63, 0xbd, 0xc0, 0xc0, + 0x49, 0x7d, 0xc0, 0x08, 0x00, 0x4a, 0xbb, 0x37, 0x12, 0x69, 0xbe, 0xb4, + 0xc0, 0x01, 0xbe, 0xbd, 0x85, 0xc0, 0x03, 0x6e, 0x0b, 0x3f, 0xac, 0x82, + 0xc0, 0x01, 0x9d, 0xbf, 0x82, 0xc0, 0x01, 0x88, 0x92, 0x83, 0xc0, 0x01, + 0x9d, 0xbf, 0x81, 0xc0, 0x03, 0xbb, 0x44, 0x48, 0xba, 0x89, 0xc0, 0x04, + 0xb8, 0xc0, 0xc0, 0x93, 0x9d, 0x88, 0xc0, 0x01, 0x88, 0x92, 0xe1, 0xc0, + 0x03, 0xb4, 0x2d, 0x1f, 0xbb, 0xff, 0xc0, 0x03, 0xbb, 0x2c, 0x05, 0x9a, + 0xff, 0xc0, 0x03, 0xc0, 0x65, 0x00, 0x77, 0xff, 0xc0, 0x03, 0xc0, 0xc0, + 0x30, 0x78, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xc8, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x8e, 0xc0, 0x08, 0xb2, 0x98, 0x83, + 0x6e, 0x5a, 0x45, 0x30, 0x1b, 0x39, 0xa8, 0xc0, 0x00, 0xf3, 0x8c, 0xff, + 0x00, 0xe7, 0x81, 0xc0, 0x00, 0xe4, 0x8c, 0xff, 0x03, 0xfb, 0xc0, 0xca, + 0xfe, 0x84, 0xff, 0x00, 0xf9, 0x9f, 0xc0, 0x01, 0x6e, 0x0b, 0x83, 0x00, + 0x00, 0x5a, 0xa8, 0xc0, 0x01, 0xc2, 0xf6, 0x8b, 0xff, 0x00, 0xea, 0x82, + 0xc0, 0x00, 0xe9, 0x8b, 0xff, 0x03, 0xfe, 0xc0, 0xc0, 0xd0, 0x83, 0xff, + 0x01, 0xea, 0xc3, 0xa0, 0xc0, 0x01, 0xb9, 0x15, 0x82, 0x00, 0x00, 0x82, + 0xa9, 0xc0, 0x00, 0xe5, 0x82, 0xff, 0x09, 0xf9, 0xd5, 0xc9, 0xc8, 0xcf, + 0xda, 0xf4, 0xff, 0xff, 0xed, 0x82, 0xc0, 0x00, 0xd6, 0x82, 0xff, 0x0d, + 0xfb, 0xd9, 0xcb, 0xc7, 0xcd, 0xd4, 0xea, 0xfe, 0xff, 0xff, 0xc2, 0xc0, + 0xc0, 0xfd, 0x82, 0xff, 0x00, 0xca, 0xa2, 0xc0, 0x00, 0x15, 0x82, 0x00, + 0x00, 0xaa, 0xa9, 0xc0, 0x00, 0xec, 0x82, 0xff, 0x00, 0xd9, 0x83, 0xc0, + 0x02, 0xde, 0xff, 0xf0, 0x82, 0xc0, 0x00, 0xde, 0x82, 0xff, 0x00, 0xe3, + 0x83, 0xc0, 0x05, 0xcc, 0xfa, 0xff, 0xc5, 0xc0, 0xc5, 0x82, 0xff, 0x00, + 0xf5, 0xa2, 0xc0, 0x00, 0xad, 0x82, 0x00, 0x01, 0x11, 0xbf, 0xa9, 0xc0, + 0x00, 0xf9, 0x82, 0xff, 0x00, 0xc7, 0x80, 0xc0, 0x05, 0xc4, 0xfe, 0xc0, + 0xc0, 0xe8, 0xf2, 0x82, 0xc0, 0x00, 0xea, 0x82, 0xff, 0x00, 0xd4, 0x80, + 0xc0, 0x08, 0xc5, 0xfb, 0xc0, 0xc0, 0xcf, 0xff, 0xc8, 0xc0, 0xd0, 0x82, + 0xff, 0x00, 0xe8, 0xa2, 0xc0, 0x00, 0x85, 0x82, 0x00, 0x00, 0x3a, 0x98, + 0xc0, 0x11, 0xb3, 0x95, 0x7a, 0x60, 0x45, 0x2a, 0x0f, 0x66, 0xc0, 0xc0, + 0xa4, 0x58, 0x20, 0x0b, 0x69, 0xc0, 0xc0, 0xc6, 0x82, 0xff, 0x00, 0xf6, + 0x80, 0xc0, 0x06, 0xc5, 0xe8, 0xff, 0xc0, 0xc0, 0xce, 0xf5, 0x82, 0xc0, + 0x00, 0xf7, 0x82, 0xff, 0x05, 0xc5, 0xc0, 0xc0, 0xc3, 0xe4, 0xff, 0x80, + 0xc0, 0x03, 0xeb, 0xc9, 0xc0, 0xdd, 0x82, 0xff, 0x14, 0xdb, 0xc0, 0xc0, + 0xaf, 0x91, 0x77, 0x5d, 0x42, 0x28, 0x0e, 0x91, 0xc0, 0xc0, 0xb4, 0x70, + 0x34, 0x15, 0x05, 0x17, 0x53, 0xb5, 0x87, 0xc0, 0x04, 0x9d, 0x60, 0x2e, + 0x16, 0x08, 0x85, 0x00, 0x00, 0x63, 0x98, 0xc0, 0x00, 0x68, 0x83, 0x00, + 0x0a, 0x16, 0xc0, 0x6f, 0x05, 0x00, 0x00, 0x09, 0xb5, 0xc0, 0xc0, 0xd3, + 0x82, 0xff, 0x06, 0xfd, 0xf5, 0xf6, 0xf9, 0xfe, 0xff, 0xff, 0x80, 0xc0, + 0x00, 0xc9, 0x81, 0xc0, 0x00, 0xc5, 0x83, 0xff, 0x05, 0xf5, 0xf6, 0xf8, + 0xfe, 0xff, 0xff, 0x83, 0xc0, 0x00, 0xea, 0x82, 0xff, 0x03, 0xcf, 0xc0, + 0xc0, 0x51, 0x83, 0x00, 0x03, 0x5d, 0xbe, 0x6d, 0x0e, 0x83, 0x00, 0x00, + 0x4a, 0x85, 0xc0, 0x01, 0xa7, 0x3c, 0x8a, 0x00, 0x00, 0x8b, 0x99, 0xc0, + 0x00, 0x87, 0x82, 0x00, 0x01, 0x05, 0x6e, 0x81, 0x00, 0x00, 0x54, 0x80, + 0xc0, 0x00, 0xe0, 0x89, 0xff, 0x85, 0xc0, 0x00, 0xd2, 0x89, 0xff, 0x83, + 0xc0, 0x00, 0xf6, 0x82, 0xff, 0x00, 0xc3, 0x80, 0xc0, 0x00, 0x68, 0x82, + 0x00, 0x01, 0x42, 0x39, 0x85, 0x00, 0x00, 0x0f, 0x84, 0xc0, 0x01, 0x8f, + 0x0e, 0x84, 0x00, 0x01, 0x12, 0x02, 0x82, 0x00, 0x00, 0xb2, 0x99, 0xc0, + 0x00, 0xb8, 0x82, 0x00, 0x06, 0x02, 0x02, 0x0e, 0x31, 0x14, 0x02, 0xa7, + 0x80, 0xc0, 0x00, 0xed, 0x89, 0xff, 0x85, 0xc0, 0x00, 0xdf, 0x89, 0xff, + 0x82, 0xc0, 0x00, 0xc4, 0x82, 0xff, 0x00, 0xf5, 0x81, 0xc0, 0x00, 0x8b, + 0x84, 0x00, 0x02, 0x2c, 0x62, 0x3a, 0x82, 0x00, 0x00, 0x12, 0x83, 0xc0, + 0x01, 0x99, 0x06, 0x82, 0x00, 0x04, 0x1b, 0x84, 0xb2, 0xb5, 0x01, 0x81, + 0x00, 0x00, 0x1a, 0x9a, 0xc0, 0x00, 0xa2, 0x83, 0x00, 0x04, 0x38, 0xb8, + 0xc0, 0xbd, 0x8a, 0x81, 0xc0, 0x00, 0xfa, 0x82, 0xff, 0x06, 0xcf, 0xc3, + 0xc3, 0xcb, 0xe2, 0xfe, 0xff, 0x85, 0xc0, 0x00, 0xec, 0x82, 0xff, 0x06, + 0xdb, 0xc4, 0xc3, 0xcb, 0xe4, 0xff, 0xff, 0x82, 0xc0, 0x00, 0xd0, 0x82, + 0xff, 0x00, 0xe9, 0x81, 0xc0, 0x00, 0x72, 0x83, 0x00, 0x03, 0x4c, 0xbe, + 0xc0, 0xb2, 0x82, 0x00, 0x00, 0x35, 0x82, 0xc0, 0x01, 0xb2, 0x14, 0x82, + 0x00, 0x04, 0x4e, 0xba, 0xc0, 0xc0, 0x8d, 0x82, 0x00, 0x00, 0x42, 0x9a, + 0xc0, 0x00, 0x7b, 0x82, 0x00, 0x01, 0x07, 0xaf, 0x84, 0xc0, 0x00, 0xc8, + 0x82, 0xff, 0x00, 0xfb, 0x82, 0xc0, 0x01, 0xdc, 0xff, 0x85, 0xc0, 0x00, + 0xf9, 0x82, 0xff, 0x00, 0xc9, 0x81, 0xc0, 0x01, 0xe2, 0xff, 0x82, 0xc0, + 0x00, 0xdd, 0x82, 0xff, 0x00, 0xdc, 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, + 0x04, 0x16, 0xbb, 0xc0, 0xc0, 0xa7, 0x82, 0x00, 0x00, 0x59, 0x82, 0xc0, + 0x00, 0x54, 0x82, 0x00, 0x01, 0x3b, 0xbe, 0x80, 0xc0, 0x00, 0x63, 0x82, + 0x00, 0x00, 0x6b, 0x9a, 0xc0, 0x00, 0x52, 0x82, 0x00, 0x00, 0x45, 0x85, + 0xc0, 0x00, 0xd5, 0x82, 0xff, 0x00, 0xed, 0x82, 0xc0, 0x01, 0xc3, 0xfe, + 0x84, 0xc0, 0x00, 0xc6, 0x82, 0xff, 0x00, 0xfc, 0x82, 0xc0, 0x01, 0xca, + 0xff, 0x82, 0xc0, 0x00, 0xe9, 0x82, 0xff, 0x00, 0xcf, 0x81, 0xc0, 0x00, + 0x28, 0x82, 0x00, 0x00, 0x6f, 0x80, 0xc0, 0x00, 0x78, 0x82, 0x00, 0x00, + 0x8a, 0x81, 0xc0, 0x01, 0xab, 0x04, 0x81, 0x00, 0x01, 0x08, 0xac, 0x81, + 0xc0, 0x00, 0x3a, 0x82, 0x00, 0x00, 0x93, 0x9a, 0xc0, 0x00, 0x29, 0x82, + 0x00, 0x00, 0x79, 0x85, 0xc0, 0x00, 0xe2, 0x82, 0xff, 0x00, 0xe0, 0x83, + 0xc0, 0x00, 0xc1, 0x84, 0xc0, 0x00, 0xd3, 0x82, 0xff, 0x00, 0xef, 0x83, + 0xc0, 0x00, 0xc8, 0x82, 0xc0, 0x00, 0xf6, 0x82, 0xff, 0x00, 0xc3, 0x80, + 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xaf, 0x80, 0xc0, 0x00, 0x40, + 0x81, 0x00, 0x01, 0x04, 0xb8, 0x81, 0xc0, 0x00, 0x6b, 0x82, 0x00, 0x00, + 0x51, 0x81, 0xc0, 0x01, 0xbf, 0x11, 0x81, 0x00, 0x01, 0x02, 0xb8, 0x99, + 0xc0, 0x01, 0xbb, 0x05, 0x82, 0x00, 0x00, 0xa8, 0x85, 0xc0, 0x00, 0xef, + 0x82, 0xff, 0x00, 0xd2, 0x86, 0xc0, 0x01, 0xc9, 0xe7, 0x80, 0xc0, 0x00, + 0xe0, 0x82, 0xff, 0x00, 0xe2, 0x88, 0xc0, 0x00, 0xc4, 0x82, 0xff, 0x00, + 0xf6, 0x81, 0xc0, 0x00, 0x9b, 0x82, 0x00, 0x00, 0x25, 0x80, 0xc0, 0x01, + 0xbc, 0x0b, 0x81, 0x00, 0x00, 0x2f, 0x82, 0xc0, 0x00, 0x31, 0x82, 0x00, + 0x00, 0x8f, 0x81, 0xc0, 0x00, 0xa8, 0x82, 0x00, 0x00, 0x23, 0x9a, 0xc0, + 0x00, 0x99, 0x82, 0x00, 0x01, 0x10, 0xbf, 0x85, 0xc0, 0x00, 0xfc, 0x82, + 0xff, 0x00, 0xc6, 0x85, 0xc0, 0x02, 0xc4, 0xf6, 0xdf, 0x80, 0xc0, 0x00, + 0xed, 0x82, 0xff, 0x00, 0xd5, 0x88, 0xc0, 0x00, 0xd0, 0x82, 0xff, 0x00, + 0xe9, 0x81, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x57, 0x80, 0xc0, 0x00, + 0x91, 0x82, 0x00, 0x00, 0x62, 0x82, 0xc0, 0x00, 0x15, 0x82, 0x00, 0x00, + 0xaf, 0x81, 0xc0, 0x00, 0x7f, 0x82, 0x00, 0x00, 0x4b, 0x9a, 0xc0, 0x00, + 0x6f, 0x82, 0x00, 0x00, 0x39, 0x85, 0xc0, 0x00, 0xc9, 0x82, 0xff, 0x00, + 0xfb, 0x85, 0xc0, 0x03, 0xc2, 0xee, 0xfd, 0xc5, 0x80, 0xc0, 0x00, 0xfa, + 0x82, 0xff, 0x00, 0xc9, 0x88, 0xc0, 0x00, 0xdd, 0x82, 0xff, 0x00, 0xdd, + 0x81, 0xc0, 0x00, 0x4e, 0x82, 0x00, 0x00, 0x81, 0x80, 0xc0, 0x00, 0x5a, + 0x82, 0x00, 0x00, 0x8f, 0x82, 0xc0, 0x00, 0x05, 0x82, 0x00, 0x00, 0xb7, + 0x81, 0xc0, 0x00, 0x55, 0x82, 0x00, 0x00, 0x73, 0x9a, 0xc0, 0x00, 0x47, + 0x82, 0x00, 0x00, 0x62, 0x85, 0xc0, 0x00, 0xd6, 0x82, 0xff, 0x00, 0xf2, + 0x84, 0xc0, 0x03, 0xc7, 0xf3, 0xff, 0xe4, 0x80, 0xc0, 0x00, 0xc8, 0x82, + 0xff, 0x00, 0xfb, 0x89, 0xc0, 0x00, 0xe9, 0x82, 0xff, 0x00, 0xd0, 0x81, + 0xc0, 0x00, 0x28, 0x82, 0x00, 0x00, 0xa9, 0x80, 0xc0, 0x00, 0x2b, 0x82, + 0x00, 0x00, 0xb4, 0x82, 0xc0, 0x00, 0x14, 0x82, 0x00, 0x00, 0x97, 0x81, + 0xc0, 0x00, 0x2c, 0x82, 0x00, 0x00, 0x9c, 0x9a, 0xc0, 0x00, 0x1e, 0x82, + 0x00, 0x00, 0x8b, 0x85, 0xc0, 0x00, 0xe4, 0x82, 0xff, 0x01, 0xf9, 0xc2, + 0x81, 0xc0, 0x05, 0xc3, 0xda, 0xfa, 0xff, 0xfe, 0xc7, 0x80, 0xc0, 0x00, + 0xd5, 0x82, 0xff, 0x00, 0xef, 0x89, 0xc0, 0x00, 0xf7, 0x82, 0xff, 0x00, + 0xc4, 0x80, 0xc0, 0x01, 0xbb, 0x05, 0x81, 0x00, 0x01, 0x12, 0xbf, 0x80, + 0xc0, 0x00, 0x0e, 0x82, 0x00, 0x01, 0x7b, 0xbd, 0x81, 0xc0, 0x00, 0x41, + 0x82, 0x00, 0x05, 0x3e, 0xbf, 0xc0, 0xc0, 0xaf, 0x04, 0x81, 0x00, 0x01, + 0x06, 0xbc, 0x99, 0xc0, 0x00, 0xb5, 0x83, 0x00, 0x00, 0xb3, 0x85, 0xc0, + 0x00, 0xf8, 0x83, 0xff, 0x05, 0xf0, 0xda, 0xd7, 0xdf, 0xe8, 0xfb, 0x80, + 0xff, 0x00, 0xe8, 0x81, 0xc0, 0x00, 0xe9, 0x82, 0xff, 0x00, 0xe9, 0x88, + 0xc0, 0x00, 0xcb, 0x82, 0xff, 0x00, 0xfd, 0x81, 0xc0, 0x00, 0x9b, 0x82, + 0x00, 0x00, 0x3b, 0x81, 0xc0, 0x00, 0x12, 0x83, 0x00, 0x06, 0x0b, 0x21, + 0xb2, 0xc0, 0xc0, 0x97, 0x02, 0x82, 0x00, 0x03, 0x42, 0x97, 0xa7, 0x49, + 0x82, 0x00, 0x00, 0x18, 0x9a, 0xc0, 0x00, 0x8e, 0x82, 0x00, 0x00, 0x1d, + 0x84, 0xc0, 0x01, 0xc1, 0xdb, 0x8d, 0xff, 0x00, 0xcb, 0x80, 0xc0, 0x01, + 0xd0, 0xfd, 0x82, 0xff, 0x01, 0xf9, 0xc3, 0x86, 0xc0, 0x01, 0xc3, 0xea, + 0x83, 0xff, 0x00, 0xd0, 0x80, 0xc0, 0x00, 0x75, 0x82, 0x00, 0x00, 0x64, + 0x81, 0xc0, 0x00, 0x60, 0x82, 0x00, 0x02, 0x2f, 0x7e, 0xbb, 0x81, 0xc0, + 0x01, 0x75, 0x05, 0x8b, 0x00, 0x00, 0x88, 0x99, 0xc0, 0x00, 0x65, 0x82, + 0x00, 0x00, 0x45, 0x84, 0xc0, 0x00, 0xea, 0x8d, 0xff, 0x00, 0xec, 0x80, + 0xc0, 0x00, 0xdb, 0x85, 0xff, 0x00, 0xf7, 0x86, 0xc0, 0x00, 0xf9, 0x84, + 0xff, 0x04, 0xfe, 0xca, 0xc0, 0xc0, 0x4e, 0x82, 0x00, 0x00, 0x8e, 0x81, + 0xc0, 0x05, 0xbe, 0x76, 0x29, 0x10, 0x52, 0xa0, 0x85, 0xc0, 0x05, 0xa4, + 0x5a, 0x2b, 0x11, 0x0a, 0x04, 0x87, 0x00, 0x00, 0x92, 0xff, 0xc0, 0xff, + 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, + 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xd6, 0xc0, 0x09, + 0xb1, 0x85, 0x5a, 0x38, 0x1b, 0x08, 0x05, 0x16, 0x4b, 0xad, 0x95, 0xc0, + 0x03, 0x97, 0x49, 0x10, 0x68, 0x81, 0xc0, 0x01, 0x83, 0xa0, 0x80, 0xc0, + 0x01, 0xbe, 0xa1, 0xd1, 0xc0, 0x02, 0xb8, 0x41, 0x01, 0x85, 0x00, 0x00, + 0x29, 0x92, 0xc0, 0x02, 0x93, 0x60, 0x2f, 0x80, 0x00, 0x0c, 0x13, 0xc0, + 0xc0, 0xb0, 0x35, 0x00, 0x36, 0xc0, 0xc0, 0xb2, 0x2f, 0x03, 0x99, 0xd0, + 0xc0, 0x0b, 0x3a, 0x00, 0x01, 0x2f, 0x60, 0x85, 0xa3, 0xb4, 0xbd, 0xb0, + 0x72, 0x0e, 0x91, 0xc0, 0x13, 0x7f, 0x02, 0x00, 0x00, 0x14, 0x72, 0xab, + 0x18, 0xc0, 0xaa, 0x1b, 0x10, 0x00, 0x58, 0xc0, 0x9d, 0x1a, 0x00, 0x04, + 0x97, 0xcf, 0xc0, 0x0c, 0x89, 0x05, 0x26, 0x53, 0xaf, 0xc0, 0x9f, 0x48, + 0xa3, 0xc0, 0xc0, 0x8c, 0x6b, 0x8b, 0xc0, 0x02, 0xaf, 0x4b, 0x9f, 0x80, + 0xc0, 0x12, 0x2a, 0x00, 0x08, 0x60, 0xb8, 0xc0, 0x89, 0x4d, 0xad, 0x1d, + 0x7a, 0x5f, 0x05, 0xab, 0x90, 0x09, 0x00, 0x01, 0x7c, 0xbc, 0xc0, 0x02, + 0xaf, 0x4b, 0x9f, 0x8e, 0xc0, 0x01, 0xbf, 0xbe, 0x80, 0xc0, 0x06, 0x91, + 0x22, 0x8c, 0x8a, 0x65, 0x4b, 0x82, 0x8c, 0xc0, 0x02, 0x31, 0x38, 0xbf, + 0x80, 0xc0, 0x02, 0x14, 0x50, 0xac, 0x80, 0xc0, 0x0b, 0x2f, 0x8e, 0x25, + 0x78, 0xb2, 0x0f, 0x54, 0x94, 0x08, 0x4b, 0x08, 0x61, 0xbd, 0xc0, 0x02, + 0x31, 0x38, 0xbf, 0x92, 0xc0, 0x06, 0xa3, 0x0e, 0x14, 0x32, 0x5b, 0x91, + 0xbf, 0x8a, 0xc0, 0x05, 0x60, 0x0e, 0x01, 0x00, 0x13, 0xb1, 0x85, 0xc0, + 0x0b, 0x85, 0x24, 0x3d, 0x5e, 0xc0, 0x49, 0x0c, 0x8f, 0x0e, 0x6f, 0x41, + 0x38, 0xbb, 0xc0, 0x05, 0x60, 0x0e, 0x01, 0x00, 0x13, 0xb1, 0x8f, 0xc0, + 0x06, 0x9b, 0x23, 0x11, 0x02, 0x48, 0x98, 0xba, 0x82, 0xc0, 0x0f, 0x94, + 0x30, 0x08, 0x64, 0xc0, 0xc0, 0x94, 0x30, 0x08, 0x64, 0x7d, 0x0b, 0x06, + 0x00, 0x00, 0x75, 0x85, 0xc0, 0x0c, 0xb6, 0x15, 0x19, 0x38, 0xbf, 0x8f, + 0x01, 0x51, 0x14, 0x75, 0x66, 0x10, 0xb0, 0x80, 0xc0, 0x0b, 0x96, 0x40, + 0x0d, 0x7b, 0xc0, 0xc0, 0xb6, 0x70, 0xbe, 0xc0, 0x65, 0x25, 0x80, 0xc0, + 0x03, 0x96, 0x40, 0x0d, 0x7b, 0x80, 0xc0, 0x03, 0xbe, 0x77, 0x23, 0x28, + 0x81, 0xc0, 0x03, 0xa9, 0x4a, 0x0d, 0x23, 0x89, 0xc0, 0x11, 0xa9, 0x4a, + 0x0d, 0x23, 0xc0, 0xc0, 0xb6, 0x70, 0xbe, 0xc0, 0x65, 0x25, 0x7d, 0x0b, + 0x06, 0x00, 0x00, 0x75, 0x91, 0xc0, 0x01, 0x8b, 0x01, 0x80, 0x00, 0x14, + 0x05, 0x32, 0x7a, 0xbe, 0xc0, 0x70, 0x02, 0x25, 0x57, 0x1d, 0xc0, 0x70, + 0x02, 0x25, 0x57, 0x1d, 0xbb, 0xac, 0x15, 0x86, 0xb5, 0x86, 0xc0, 0x4e, + 0x51, 0x00, 0x15, 0xb2, 0xb5, 0x17, 0x0d, 0x1a, 0x71, 0x94, 0x02, 0x77, + 0xc0, 0xc0, 0xb7, 0x47, 0x15, 0x60, 0x11, 0xa5, 0xc0, 0xc0, 0x38, 0x44, + 0xbc, 0x48, 0x00, 0x30, 0xc0, 0xb7, 0x47, 0x15, 0x60, 0x11, 0xa5, 0xc0, + 0xc0, 0xae, 0x2f, 0x00, 0x27, 0x69, 0x1b, 0xc0, 0xc0, 0x8b, 0x0b, 0x50, + 0x85, 0x39, 0xc0, 0xb3, 0x5e, 0x5d, 0xba, 0x53, 0x0e, 0x9f, 0xc0, 0x91, + 0x5a, 0x8b, 0x0b, 0x50, 0x85, 0x39, 0xc0, 0xc0, 0x38, 0x44, 0xbc, 0x48, + 0x00, 0x30, 0xbb, 0xac, 0x15, 0x86, 0xb5, 0x91, 0xc0, 0x18, 0xb6, 0x17, + 0x0c, 0x96, 0xad, 0x91, 0x6d, 0x2d, 0x00, 0x3f, 0x88, 0x01, 0x54, 0xbd, + 0x3a, 0x09, 0x88, 0x01, 0x54, 0xbd, 0x3a, 0x09, 0xae, 0x1f, 0x3f, 0x87, + 0xc0, 0x4d, 0x8e, 0x01, 0x02, 0x91, 0xc0, 0x42, 0x00, 0x00, 0x63, 0xbc, + 0x1e, 0x1f, 0xbe, 0xc0, 0xae, 0x23, 0x60, 0xb8, 0x3a, 0x0f, 0xab, 0xc0, + 0x82, 0x12, 0xb4, 0x48, 0x2f, 0x06, 0xa6, 0xae, 0x23, 0x60, 0xb8, 0x3a, + 0x0f, 0xab, 0xc0, 0xb0, 0x1c, 0x0c, 0x73, 0xac, 0x10, 0x26, 0xc0, 0x94, + 0x04, 0x5a, 0x7f, 0x5a, 0xb8, 0xa5, 0x19, 0x17, 0x7e, 0x26, 0x00, 0x0a, + 0xb3, 0x7f, 0x05, 0x00, 0x04, 0x5a, 0x7f, 0x5a, 0xb8, 0xc0, 0x82, 0x12, + 0xb4, 0x48, 0x2f, 0x06, 0xa6, 0xae, 0x1f, 0x3f, 0x93, 0xc0, 0x02, 0x5a, + 0x00, 0x90, 0x81, 0xc0, 0x14, 0xa3, 0x00, 0x0e, 0x23, 0x50, 0xc0, 0xc0, + 0x12, 0x32, 0x23, 0x50, 0xc0, 0xc0, 0x12, 0x1d, 0x3d, 0x00, 0x98, 0xc0, + 0x9f, 0xb5, 0x83, 0xc0, 0x51, 0xb2, 0x15, 0x00, 0x57, 0xc0, 0x77, 0x00, + 0x00, 0x51, 0xc0, 0x74, 0x00, 0x72, 0xc0, 0xc0, 0x33, 0x7b, 0xc0, 0x57, + 0x08, 0x8b, 0xc0, 0xa1, 0x25, 0x73, 0x63, 0x50, 0x1b, 0x56, 0xc0, 0x33, + 0x7d, 0xc0, 0x57, 0x08, 0x8b, 0xc0, 0xa1, 0x42, 0x11, 0xa2, 0xbe, 0x33, + 0x00, 0x6c, 0xc0, 0x2a, 0x00, 0x5f, 0xa1, 0xc0, 0x85, 0x2f, 0x2c, 0x9e, + 0x1c, 0x74, 0x29, 0x65, 0x72, 0x32, 0x10, 0x0b, 0x00, 0x5f, 0xa1, 0xc0, + 0x85, 0xb2, 0x25, 0x73, 0x63, 0x50, 0x1b, 0x56, 0xab, 0x3d, 0x00, 0x98, + 0xc0, 0x9f, 0xb5, 0x90, 0xc0, 0x1b, 0x11, 0x00, 0x79, 0xb9, 0xb8, 0x98, + 0x5d, 0x0e, 0x00, 0x6e, 0x06, 0x9d, 0xc0, 0xc0, 0x09, 0x63, 0x00, 0x9d, + 0xc0, 0xc0, 0x09, 0x60, 0x00, 0x00, 0xa9, 0x71, 0x3d, 0xbc, 0x83, 0xc0, + 0x51, 0x3f, 0x00, 0x1b, 0xb9, 0xb2, 0x0a, 0x00, 0x3b, 0xbe, 0xc0, 0x2c, + 0x00, 0xac, 0xc0, 0xb9, 0x00, 0x89, 0x4a, 0x36, 0x27, 0x7d, 0x55, 0x60, + 0x02, 0x7b, 0x35, 0x69, 0x00, 0xa5, 0xa0, 0x00, 0xa5, 0x4a, 0x36, 0x27, + 0x7d, 0x55, 0x60, 0x08, 0x87, 0xc0, 0x51, 0x0d, 0x08, 0xb3, 0xac, 0x06, + 0x00, 0x99, 0xa9, 0x53, 0x45, 0x0b, 0x84, 0x15, 0x78, 0x95, 0x21, 0x5a, + 0x79, 0x07, 0x91, 0x06, 0x00, 0x99, 0xa9, 0x53, 0x45, 0xc0, 0x02, 0x7b, + 0x35, 0x69, 0x00, 0xa5, 0x9e, 0x08, 0x00, 0xa9, 0x71, 0x3d, 0xbc, 0x90, + 0xc0, 0x00, 0x1b, 0x83, 0x00, 0x0e, 0x17, 0x83, 0xc0, 0x32, 0x9f, 0xb0, + 0x63, 0x24, 0x54, 0x22, 0x9f, 0xb0, 0x63, 0x24, 0x54, 0x80, 0x00, 0x01, + 0x3b, 0xb9, 0x84, 0xc0, 0x2e, 0x17, 0x00, 0x90, 0xc0, 0x91, 0x00, 0x27, + 0xb8, 0xc0, 0xc0, 0x08, 0x00, 0xa4, 0x8d, 0x21, 0x00, 0x00, 0x17, 0xb1, + 0x0b, 0x00, 0x3f, 0xbf, 0x0e, 0x0c, 0xad, 0x1a, 0x00, 0x6a, 0x39, 0x16, + 0x00, 0x17, 0xb1, 0x0b, 0x00, 0x3f, 0xbf, 0x1c, 0xa8, 0x50, 0x23, 0x50, + 0x45, 0x5c, 0x81, 0x1b, 0x80, 0x00, 0x0b, 0x39, 0xbb, 0x0c, 0x00, 0x6a, + 0xc0, 0x39, 0x1d, 0x8b, 0x40, 0x00, 0x73, 0x81, 0x00, 0x09, 0x39, 0xbb, + 0xc0, 0x0e, 0x0c, 0xad, 0x1a, 0x00, 0x6a, 0x39, 0x80, 0x00, 0x01, 0x3b, + 0xb9, 0x91, 0xc0, 0x19, 0x9d, 0x37, 0x0e, 0x04, 0x17, 0x45, 0x8b, 0xbe, + 0xc0, 0xc0, 0xa4, 0x23, 0x0a, 0x51, 0xb8, 0xc0, 0xa4, 0x23, 0x0a, 0x51, + 0xb8, 0xc0, 0x37, 0x12, 0x69, 0xbe, 0x85, 0xc0, 0x06, 0x57, 0x43, 0xc0, + 0xc0, 0xaf, 0x23, 0xae, 0x80, 0xc0, 0x45, 0x0e, 0x00, 0x00, 0x11, 0x93, + 0x88, 0x19, 0x9e, 0xc0, 0x05, 0x3b, 0xbb, 0xc0, 0x49, 0x7d, 0xc0, 0x08, + 0x00, 0x4a, 0xbb, 0x88, 0x19, 0x9e, 0xc0, 0x05, 0x3b, 0xbb, 0xc0, 0x77, + 0x0c, 0x57, 0xae, 0x0d, 0x29, 0xa3, 0xc0, 0x85, 0x11, 0x14, 0x63, 0xbd, + 0xc0, 0x55, 0x48, 0xc0, 0xc0, 0x0c, 0x75, 0xc0, 0x0c, 0x00, 0x3d, 0x73, + 0x11, 0x14, 0x63, 0xbd, 0xc0, 0xc0, 0x49, 0x7d, 0xc0, 0x08, 0x00, 0x4a, + 0xbb, 0x37, 0x12, 0x69, 0xbe, 0xb4, 0xc0, 0x01, 0xbe, 0xbd, 0x85, 0xc0, + 0x03, 0x6e, 0x0b, 0x3f, 0xac, 0x82, 0xc0, 0x01, 0x9d, 0xbf, 0x82, 0xc0, + 0x01, 0x88, 0x92, 0x83, 0xc0, 0x01, 0x9d, 0xbf, 0x81, 0xc0, 0x03, 0xbb, + 0x44, 0x48, 0xba, 0x89, 0xc0, 0x04, 0xb8, 0xc0, 0xc0, 0x93, 0x9d, 0x88, + 0xc0, 0x01, 0x88, 0x92, 0xe1, 0xc0, 0x03, 0xb4, 0x2d, 0x1f, 0xbb, 0xff, + 0xc0, 0x03, 0xbb, 0x2c, 0x05, 0x9a, 0xff, 0xc0, 0x03, 0xc0, 0x65, 0x00, + 0x77, 0xff, 0xc0, 0x03, 0xc0, 0xc0, 0x30, 0x78, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xc8, 0xc0, +}; +static EG_EMBEDDED_IMAGE egemb_refind_banner = { 135, 64, EG_EIPIXELMODE_COLOR, EG_EICOMPMODE_RLE, egemb_refind_banner_data, 7592 }; diff --git a/include/refit_call_wrapper.h b/include/refit_call_wrapper.h new file mode 100644 index 0000000..9b1f5c1 --- /dev/null +++ b/include/refit_call_wrapper.h @@ -0,0 +1,37 @@ +#ifndef __REFIT_CALL_WRAPPER_H__ +#define __REFIT_CALL_WRAPPER_H__ + +#ifdef EFIX64 +# define refit_call1_wrapper(f, a1) \ + uefi_call_wrapper(f, 1, (UINT64)(a1)) +# define refit_call2_wrapper(f, a1, a2) \ + uefi_call_wrapper(f, 2, (UINT64)(a1), (UINT64)(a2)) +# define refit_call3_wrapper(f, a1, a2, a3) \ + uefi_call_wrapper(f, 3, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3)) +# define refit_call4_wrapper(f, a1, a2, a3, a4) \ + uefi_call_wrapper(f, 4, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4)) +# define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ + uefi_call_wrapper(f, 5, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5)) +# define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ + uefi_call_wrapper(f, 6, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6)) +# define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + uefi_call_wrapper(f, 10, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), (UINT64)(a9), (UINT64)(a10)) +#else +# define refit_call1_wrapper(f, a1) \ + uefi_call_wrapper(f, 1, a1) +# define refit_call2_wrapper(f, a1, a2) \ + uefi_call_wrapper(f, 2, a1, a2) +# define refit_call3_wrapper(f, a1, a2, a3) \ + uefi_call_wrapper(f, 3, a1, a2, a3) +# define refit_call4_wrapper(f, a1, a2, a3, a4) \ + uefi_call_wrapper(f, 4, a1, a2, a3, a4) +# define refit_call5_wrapper(f, a1, a2, a3, a4, a5) \ + uefi_call_wrapper(f, 5, a1, a2, a3, a4, a5) +# define refit_call6_wrapper(f, a1, a2, a3, a4, a5, a6) \ + uefi_call_wrapper(f, 6, a1, a2, a3, a4, a5, a6) +# define refit_call10_wrapper(f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + uefi_call_wrapper(f, 10, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) +#endif + +#endif /* !__REFIT_CALL_WRAPPER_H__ */ + diff --git a/include/syslinux_mbr.h b/include/syslinux_mbr.h new file mode 100644 index 0000000..1c33e11 --- /dev/null +++ b/include/syslinux_mbr.h @@ -0,0 +1,90 @@ +/* + * include/syslinux_mbr.h + * MBR boot code + * + * The boot code in this file was taken from syslinux-3.11. It is covered + * by the following license: + * + ; ----------------------------------------------------------------------- + ; + ; Copyright 2003-2004 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 __SYSLINUX_MBR_H__ +#define __SYSLINUX_MBR_H__ + + +#define MBR_BOOTCODE_SIZE (440) + + +#define SYSLINUX_MBR_SIZE (304) + +static UINT8 syslinux_mbr[SYSLINUX_MBR_SIZE] = { + 0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0x8e, + 0xd0, 0xbc, 0x00, 0x7c, 0xfb, 0xfc, 0x89, 0xe6, + 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, + 0xea, 0x1d, 0x06, 0x00, 0x00, 0x88, 0x16, 0x00, + 0x08, 0xb4, 0x08, 0xcd, 0x13, 0x31, 0xc0, 0x88, + 0xf0, 0x40, 0xa3, 0xf0, 0x06, 0x80, 0xe1, 0x3f, + 0x88, 0x0e, 0xf2, 0x06, 0xbe, 0xbe, 0x07, 0x31, + 0xc0, 0xb9, 0x04, 0x00, 0xf6, 0x04, 0x80, 0x74, + 0x03, 0x40, 0x89, 0xf7, 0x83, 0xc6, 0x10, 0xe2, + 0xf3, 0x83, 0xf8, 0x01, 0x75, 0x73, 0x8a, 0x16, + 0x00, 0x08, 0xb8, 0x00, 0x41, 0xbb, 0xaa, 0x55, + 0x31, 0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, + 0x23, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x1d, 0xf6, + 0xc1, 0x01, 0x74, 0x18, 0x57, 0xbe, 0xe0, 0x06, + 0x8b, 0x5d, 0x08, 0x89, 0x5c, 0x08, 0x8b, 0x5d, + 0x0a, 0x89, 0x5c, 0x0a, 0x8a, 0x16, 0x00, 0x08, + 0xb4, 0x42, 0xeb, 0x2a, 0x57, 0x8b, 0x45, 0x08, + 0x8b, 0x55, 0x0a, 0xf7, 0x36, 0xf2, 0x06, 0x42, + 0x89, 0xd1, 0x31, 0xd2, 0xf7, 0x36, 0xf0, 0x06, + 0x88, 0xc5, 0xd1, 0xe8, 0xd1, 0xe8, 0x24, 0xc0, + 0x08, 0xc1, 0x88, 0xd6, 0x8a, 0x16, 0x00, 0x08, + 0xbb, 0x00, 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, + 0x72, 0x16, 0x5e, 0x81, 0x3e, 0xfe, 0x7d, 0x55, + 0xaa, 0x75, 0x08, 0xfa, 0xea, 0x00, 0x7c, 0x00, + 0x00, 0x77, 0x05, 0xbe, 0xf4, 0x06, 0xeb, 0x03, + 0xbe, 0x0f, 0x07, 0xac, 0x20, 0xc0, 0x74, 0x0c, + 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, + 0xcd, 0x10, 0xeb, 0xef, 0xeb, 0xfe, 0x00, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x73, 0x73, + 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x0d, 0x0a, 0x00, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, + 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0d, 0x0a, 0x00 +}; + + +#endif /* __SYSLINUX_MBR_H__ */ + +/* EOF */ diff --git a/mkcdimage b/mkcdimage new file mode 100755 index 0000000..613ab62 --- /dev/null +++ b/mkcdimage @@ -0,0 +1,58 @@ +#!/bin/bash +# +# Script to create a bootable CD image file containing rEFInd. +# Usage: +# +# ./mkcdimage {version} +# +# where {version} is the rEFInd version number. +# +# This script relies on the mcopy utility. +# +# The script creates an image file from the binary package +# stored in ../snapshots/{version}/refind-bin-{version}.zip +# The resulting CD image file is stored in +# ../snapshots/{version}/refind-cd-{version}.iso + +StartDir=`pwd` +Version=$1 + +# Unzip the binary archive file.... +cd ../snapshots/$Version +rm -rf temp +mkdir temp +cd temp +unzip ../refind-bin-$Version.zip + +# Create hard links to the files so that they'll be suitable for an +# EFI-boot CD... +mkdir -p refind-bin-$Version/EFI/boot +cd refind-bin-$Version/EFI/boot +ln ../../refind/refind_ia32.efi ./bootia32.efi +ln ../../refind/refind_x64.efi ./bootx64.efi +ln ../../refind/refind.conf-sample ./refind.conf +mkdir icons +cd icons +ln ../../../refind/icons/* ./ +cd ../../.. + +# Get the size of the binaries to go in the El Torito image in kB +ToritoSize=`du -s EFI | cut -f 1` +let ToritoSize=($ToritoSize)/28 +let ToritoSize=($ToritoSize)*32 + +# Prepare a FAT filesystem image and populate it with the +# EFI boot files.... +dd if=/dev/zero of=refind-bin-$Version.img bs=1024 count=$ToritoSize +mkdosfs -n "rEFInd.ET" refind-bin-$Version.img +mcopy -irefind-bin-$Version.img -s EFI ::/ + +# Make the ISO-9660 image file.... +mkisofs -A "Bootable rEFInd" -V "rEFInd $Version" -volset "rEFInd $Version" \ + -J -r -v -x ./lost+found -o ../../refind-cd-$Version.iso \ + -b refind-bin-$Version.img -c boot.cat -no-emul-boot -boot-load-size 4 \ + -eltorito-alt-boot -efi-boot refind-bin-$Version.img \ + -no-emul-boot ./ + +cd ../../ +rm -r temp/ diff --git a/mkdistrib b/mkdistrib new file mode 100755 index 0000000..fd64376 --- /dev/null +++ b/mkdistrib @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Script to prepare source code and binary distribution files of rEFInd. +# By Rod Smith, 3/11/2012 +# +# Usage: ./mkdistrib version +# where "version" is a version number +# MUST be run from an x86-64 system, on which the current IA32 build +# (refind_ia32.efi) is already present in the same directory as this script + + +StartDir=`pwd` + +make clean + +# Prepare a place and copy files there.... +mkdir -p ../snapshots/$1/refind-$1/icons +cp --preserve=timestamps icons/*icns ../snapshots/$1/refind-$1/icons/ +cp -a docs images include libeg refind NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt Make.common Makefile refind.conf-sample ../snapshots/$1/refind-$1 + +# Go there are prepare a souce code zip file.... +cd ../snapshots/$1/ +zip -9r refind-src-$1.zip refind-$1 + +# Build the source code into a binary +cd refind-$1 +make +mkdir -p refind-bin-$1/refind +cp -a icons refind-bin-$1/refind/ +cp --preserve=timestamps refind.conf-sample refind-bin-$1/refind/ +cp refind/refind.efi refind-bin-$1/refind/refind_x64.efi +cp $StartDir/refind_ia32.efi refind-bin-$1/refind/ +cp -a COPYING.txt LICENSE.txt README.txt docs refind-bin-$1 +zip -9r ../refind-bin-$1.zip refind-bin-$1 +cd .. +rm -r refind-$1 +cd $StartDir diff --git a/refind.conf-sample b/refind.conf-sample new file mode 100644 index 0000000..06ecaa9 --- /dev/null +++ b/refind.conf-sample @@ -0,0 +1,163 @@ +# +# refind.conf +# Configuration file for the rEFInd boot menu +# + +# Timeout in seconds for the main menu screen. Setting the timeout to 0 +# disables automatic booting (i.e., no timeout). +# +timeout 20 + +# Disable menu options for increased security. These are intended for a lab +# environment where the administrator doesn't want users to mess with the +# operating system. List the names for the options you want to hide from +# the boot menu. Currently supported: +# shell - remove the EFI shell +# tools - remove all EFI tools (shell and gptsync) +# singleuser - remove the submenu options to boot Mac OS X in single-user +# or verbose modes +# hwtest - remove the submenu option to run Apple Hardware Test +# all - all of the above +# +#disable shell singleuser +#disable all + +# Use a custom title banner instead of the rEFInd icon and name. The file +# path is relative to the directory where refind.efi is located. The color +# in the top left corner of the image is used as the background color +# for the menu screens. Currently uncompressed BMP images with color +# depths of 24, 8, 4 or 1 bits are supported. +# +#banner hostname.bmp + +# Custom images for the selection background. There is a big one (144 x 144) +# for the OS icons, and a small one (64 x 64) for the function icons in the +# second row. If only a small image is given, that one is also used for +# the big icons by stretching it in the middle. If only a big one is given, +# the built-in default will be used for the small icons. +# +# Like the banner option above, these options take a filename of +# an uncompressed BMP image file. +# +#selection_big selection-big.bmp +#selection_small selection-small.bmp + +# Hide various user interface elements. Here you can list the names of +# interface elements to hide. Currently supported: +# banner - the rEFInd title banner +# shell - the EFI shell icon +# tools - all EFI tools (shell and gptsync) +# funcs - built-in functions (about, restart) +# ('tools' and 'funcs' together hide the complete second row of icons.) +# label - text label in the menu +# badges - all volume badges (same as 'hidebadges all'); this setting +# is not recommended because it won't let you distinguish +# installed OSes and bootable CDs/DVDs. +# all - all of the above, except for 'badges' +# +# Note: The 'shell' and 'tools' options are equivalent to the 'disable' +# options with the same names. +# +#hideui tools funcs hdbadges +#hideui all + +# Use text mode only. When enabled, this option forces rEFInd into text mode. +# +#textonly + +# Which types of boot loaders to search: +# internal - internal EFI disk-based boot loaders +# external - external EFI disk-based boot loaders +# optical - EFI optical discs (CD, DVD, etc.) +# hdbios - BIOS disk-based boot loaders +# biosexternal - BIOS external boot loaders (USB, eSATA, etc.) +# cd - BIOS optical-disc boot loaders +# manual - use stanzas later in this configuration file +# Default is internal,external,optical +scanfor internal,external,optical + +# Set the default menu selection. The available arguments match the +# keyboard accelerators available within rEFInd. You may select the default +# loader using a one-character abbreviation for the OS name ("M" = Mac OS X, +# "L" = Linux, "W" = Windows). You may also specify a digit between 1 and +# 9, in which case the Nth loader in the menu will be the default. You can +# also select a rEFInd tool entry ("S" = EFI Shell, "P" = Partitioning Tool, +# "U" = shutdown). This is intended as a quick fix to change the default +# boot choice until full configurability arrives. +# +#default_selection 1 + +# Sample manual configuration stanzas. Each begins with the "menuentry" +# keyword followed by a name that's to appear in the menu (use quotes +# if you want the name to contain a space) and an open curly brace +# ("{"). Each entry ends with a close curly brace ("}"). Common +# keywords within each stanza include: +# +# loader - identifies the boot loader file +# initrd - Specifies an initial RAM disk file +# icon - specifies a custom boot loader icon +# ostype - OS type code to determine boot options available by +# pressing Insert. Valid values are "MacOS", "Linux", +# "Windows", and "XOM". Case-sensitive. +# graphics - set to "on" to enable graphics-mode boot (useful +# mainly for MacOS) or "off" for text-mode boot. +# Default is auto-detected from loader filename. +# options - sets options to be passed to the boot loader; use +# quotes if more than one option should be passed or +# if any options use characters that might be changed +# by rEFInd parsing procedures (=, /, #, or tab). +# disabled - use alone or set to "yes" to disable this entry. +# +# Note that you can use either DOS/Windows/EFI-style backslashes (\) +# or Unix-style forward slashes (/) as directory separators. Either +# way, all file references are on the ESP from which rEFInd was +# launched. +# Use of quotes around parameters causes them to be interpreted as +# one keyword, and for parsing of special characters (spaces, =, /, +# and #) to be disabled. This is useful mainly with the "options" +# keyword. Use of quotes around parameters that specify filenames is +# permissible, but you must then use backslashes instead of slashes, +# except when you must pass a forward slash to the loader, as when +# passing a root= option to a Linux kernel. + +# Below are several sample boot stanzas. All are disabled by default. +# Find one similar to what you need, copy it, remove the "disabled" line, +# and adjust the entries to suit your needs. + +# A sample entry for a Linux 3.3 kernel with its new EFI boot stub +# support. This includes Linux-specific boot options and specification +# of an initial RAM disk. Note uses of Linux-style forward slashes, +# even in the initrd specification. Also note that a leading slash is +# optional in file specifications. +menuentry Linux { + loader EFI/Linux/bzImage-3.3.0-rc7 + initrd EFI/Linux/initrd-3.3.0.img + icon EFI/refind/icons/os_linux.icns + options "ro root=UUID=5f96cafa-e0a7-4057-b18f-fa709db5b837" + disabled +} + +# A sample entry for loading Ubuntu using its standard name for +# its GRUB 2 boot loader. Note uses of Linux-style forward slashes +menuentry Ubuntu { + loader /EFI/ubuntu/grubx64.efi + icon /EFI/refined/icons/os_linux.icns + disabled +} + +# A minimal ELILO entry, which probably offers nothing that +# auto-detection can't accomplish. +menuentry "ELILO" { + loader \EFI\elilo\elilo.efi + disabled +} + +# Like the ELILO entry, this one offers nothing that auto-detection +# can't do; but you might use it if you want to disable auto-detection +# but still boot Windows.... +menuentry "Windows 7" { + loader \EFI\Microsoft\Boot\bootmgfw.efi + disabled +} + +# EOF diff --git a/refind/Makefile b/refind/Makefile new file mode 100644 index 0000000..4c40c48 --- /dev/null +++ b/refind/Makefile @@ -0,0 +1,30 @@ +# +# refind/Makefile +# Build control file for the rEFInd boot menu +# + +SRCDIR = . + +VPATH = $(SRCDIR) + +ifeq ($(ARCH),ia32) + LIBEG = build32 +endif + +ifeq ($(ARCH),x86_64) + LIBEG = build64 +endif + +LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -DDEBIAN_VERSION="L\"$(DEBVER)\"" +LOCAL_LDFLAGS = -L$(SRCDIR)/../libeg/$(LIBEG) +LOCAL_LIBS = -leg + +OBJS = main.o config.o menu.o screen.o icns.o lib.o +TARGET = refind.efi + +all: $(TARGET) + +include $(SRCDIR)/../Make.common + +# EOF +# DO NOT DELETE diff --git a/refind/config.c b/refind/config.c new file mode 100644 index 0000000..b89e365 --- /dev/null +++ b/refind/config.c @@ -0,0 +1,612 @@ +/* + * refit/config.c + * Configuration file functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#include "global.h" +#include "lib.h" +#include "icns.h" +#include "menu.h" +#include "config.h" +#include "screen.h" +#include "refit_call_wrapper.h" + +// constants + +#define CONFIG_FILE_NAME L"refind.conf" +#define LINUX_OPTIONS_FILENAME L"linux.conf" +#define MAXCONFIGFILESIZE (128*1024) + +#define ENCODING_ISO8859_1 (0) +#define ENCODING_UTF8 (1) +#define ENCODING_UTF16_LE (2) + +static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL }; + +// +// read a file into a buffer +// + +static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_FILE *File) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_INFO *FileInfo; + UINT64 ReadSize; + + File->Buffer = NULL; + File->BufferSize = 0; + + // read the file, allocating a buffer on the way + Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + if (CheckError(Status, L"while loading the configuration file")) + return Status; + + FileInfo = LibFileInfo(FileHandle); + if (FileInfo == NULL) { + // TODO: print and register the error + refit_call1_wrapper(FileHandle->Close, FileHandle); + return EFI_LOAD_ERROR; + } + ReadSize = FileInfo->FileSize; + if (ReadSize > MAXCONFIGFILESIZE) + ReadSize = MAXCONFIGFILESIZE; + FreePool(FileInfo); + + File->BufferSize = (UINTN)ReadSize; // was limited to a few K before, so this is safe + File->Buffer = AllocatePool(File->BufferSize); + Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &File->BufferSize, File->Buffer); + if (CheckError(Status, L"while loading the configuration file")) { + FreePool(File->Buffer); + File->Buffer = NULL; + refit_call1_wrapper(FileHandle->Close, FileHandle); + return Status; + } + Status = refit_call1_wrapper(FileHandle->Close, FileHandle); + + // setup for reading + File->Current8Ptr = (CHAR8 *)File->Buffer; + File->End8Ptr = File->Current8Ptr + File->BufferSize; + File->Current16Ptr = (CHAR16 *)File->Buffer; + File->End16Ptr = File->Current16Ptr + (File->BufferSize >> 1); + + // detect encoding + File->Encoding = ENCODING_ISO8859_1; // default: 1:1 translation of CHAR8 to CHAR16 + if (File->BufferSize >= 4) { + if (File->Buffer[0] == 0xFF && File->Buffer[1] == 0xFE) { + // BOM in UTF-16 little endian (or UTF-32 little endian) + File->Encoding = ENCODING_UTF16_LE; // use CHAR16 as is + File->Current16Ptr++; + } else if (File->Buffer[0] == 0xEF && File->Buffer[1] == 0xBB && File->Buffer[2] == 0xBF) { + // BOM in UTF-8 + File->Encoding = ENCODING_UTF8; // translate from UTF-8 to UTF-16 + File->Current8Ptr += 3; + } else if (File->Buffer[1] == 0 && File->Buffer[3] == 0) { + File->Encoding = ENCODING_UTF16_LE; // use CHAR16 as is + } + // TODO: detect other encodings as they are implemented + } + + return EFI_SUCCESS; +} + +// +// get a single line of text from a file +// + +static CHAR16 *ReadLine(REFIT_FILE *File) +{ + CHAR16 *Line, *q; + UINTN LineLength; + + if (File->Buffer == NULL) + return NULL; + + if (File->Encoding == ENCODING_ISO8859_1 || File->Encoding == ENCODING_UTF8) { + + CHAR8 *p, *LineStart, *LineEnd; + + p = File->Current8Ptr; + if (p >= File->End8Ptr) + return NULL; + + LineStart = p; + for (; p < File->End8Ptr; p++) + if (*p == 13 || *p == 10) + break; + LineEnd = p; + for (; p < File->End8Ptr; p++) + if (*p != 13 && *p != 10) + break; + File->Current8Ptr = p; + + LineLength = (UINTN)(LineEnd - LineStart) + 1; + Line = AllocatePool(LineLength * sizeof(CHAR16)); + if (Line == NULL) + return NULL; + + q = Line; + if (File->Encoding == ENCODING_ISO8859_1) { + for (p = LineStart; p < LineEnd; ) + *q++ = *p++; + } else if (File->Encoding == ENCODING_UTF8) { + // TODO: actually handle UTF-8 + for (p = LineStart; p < LineEnd; ) + *q++ = *p++; + } + *q = 0; + + } else if (File->Encoding == ENCODING_UTF16_LE) { + + CHAR16 *p, *LineStart, *LineEnd; + + p = File->Current16Ptr; + if (p >= File->End16Ptr) + return NULL; + + LineStart = p; + for (; p < File->End16Ptr; p++) + if (*p == 13 || *p == 10) + break; + LineEnd = p; + for (; p < File->End16Ptr; p++) + if (*p != 13 && *p != 10) + break; + File->Current16Ptr = p; + + LineLength = (UINTN)(LineEnd - LineStart) + 1; + Line = AllocatePool(LineLength * sizeof(CHAR16)); + if (Line == NULL) + return NULL; + + for (p = LineStart, q = Line; p < LineEnd; ) + *q++ = *p++; + *q = 0; + + } else + return NULL; // unsupported encoding + + return Line; +} + +// +// get a line of tokens from a file +// + +UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) +{ + BOOLEAN LineFinished, IsQuoted = FALSE; + CHAR16 *Line, *Token, *p; + UINTN TokenCount = 0; + + *TokenList = NULL; + + while (TokenCount == 0) { + Line = ReadLine(File); + if (Line == NULL) + return(0); + + p = Line; + LineFinished = FALSE; + while (!LineFinished) { + // skip whitespace + while ((*p == ' ' || *p == '\t' || *p == '=' || *p == ',') && !IsQuoted) + p++; + if (*p == 0 || *p == '#') + break; + + if (*p == '"') { + IsQuoted = !IsQuoted; + p++; + } // if + Token = p; + + // find end of token + while (*p && *p != '"' && ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || IsQuoted)) { + if ((*p == '/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators + *p = '\\'; + p++; + } // if + if (*p == '"') + IsQuoted = !IsQuoted; + if (*p == 0 || *p == '#') + LineFinished = TRUE; + *p++ = 0; + + AddListElement((VOID ***)TokenList, &TokenCount, (VOID *)StrDuplicate(Token)); + } + + FreePool(Line); + } + return (TokenCount); +} /* ReadTokenLine() */ + +VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount) +{ + // TODO: also free the items + FreeList((VOID ***)TokenList, TokenCount); +} + +// +// handle a parameter with a single integer argument +// + +static VOID HandleInt(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT UINTN *Value) +{ + if (TokenCount < 2) { + return; + } + if (TokenCount > 2) { + return; + } + *Value = Atoi(TokenList[1]); +} + +// +// handle a parameter with a single string argument +// + +static VOID HandleString(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Value) +{ + if (TokenCount < 2) { + return; + } + if (TokenCount > 2) { + return; + } + *Value = StrDuplicate(TokenList[1]); +} + +// +// read config file +// + +VOID ReadConfig(VOID) +{ + EFI_STATUS Status; + REFIT_FILE File; + CHAR16 **TokenList; + CHAR16 *FlagName; + UINTN TokenCount, i; + + if (!FileExists(SelfDir, CONFIG_FILE_NAME)) { + Print(L"Configuration file missing!\n"); + return; + } + + Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File); + if (EFI_ERROR(Status)) + return; + + for (;;) { + TokenCount = ReadTokenLine(&File, &TokenList); + if (TokenCount == 0) + break; + + if (StriCmp(TokenList[0], L"timeout") == 0) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.Timeout)); + + } else if (StriCmp(TokenList[0], L"disable") == 0) { + for (i = 1; i < TokenCount; i++) { + FlagName = TokenList[i]; + if (StriCmp(FlagName, L"shell") == 0) { + GlobalConfig.DisableFlags |= DISABLE_FLAG_SHELL; + } else if (StriCmp(FlagName, L"tools") == 0) { + GlobalConfig.DisableFlags |= DISABLE_FLAG_TOOLS; + } else if (StriCmp(FlagName, L"singleuser") == 0) { + GlobalConfig.DisableFlags |= DISABLE_FLAG_SINGLEUSER; + } else if (StriCmp(FlagName, L"hwtest") == 0) { + GlobalConfig.DisableFlags |= DISABLE_FLAG_HWTEST; + } else if (StriCmp(FlagName, L"all") == 0) { + GlobalConfig.DisableFlags = DISABLE_ALL; + } else { + Print(L" unknown disable flag: '%s'\n", FlagName); + } + } + + } else if (StriCmp(TokenList[0], L"scanfor") == 0) { + for (i = 0; i < NUM_SCAN_OPTIONS; i++) { + if (i < TokenCount) + GlobalConfig.ScanFor[i] = TokenList[i][0]; + else + GlobalConfig.ScanFor[i] = ' '; + } + } else if (StriCmp(TokenList[0], L"hideui") == 0) { + for (i = 1; i < TokenCount; i++) { + FlagName = TokenList[i]; + if (StriCmp(FlagName, L"banner") == 0) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_BANNER; + } else if (StriCmp(FlagName, L"shell") == 0) { + GlobalConfig.DisableFlags |= DISABLE_FLAG_SHELL; + } else if (StriCmp(FlagName, L"tools") == 0) { + GlobalConfig.DisableFlags |= DISABLE_FLAG_TOOLS; + } else if (StriCmp(FlagName, L"funcs") == 0) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_FUNCS; + } else if (StriCmp(FlagName, L"label") == 0) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_LABEL; + } else if (StriCmp(FlagName, L"all") == 0) { + GlobalConfig.HideUIFlags = HIDEUI_ALL; + GlobalConfig.DisableFlags |= DISABLE_FLAG_SHELL | DISABLE_FLAG_TOOLS; + } else { + Print(L" unknown hideui flag: '%s'\n", FlagName); + } + } + + } else if (StriCmp(TokenList[0], L"banner") == 0) { + HandleString(TokenList, TokenCount, &(GlobalConfig.BannerFileName)); + + } else if (StriCmp(TokenList[0], L"selection_small") == 0) { + HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionSmallFileName)); + + } else if (StriCmp(TokenList[0], L"selection_big") == 0) { + HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName)); + + } else if (StriCmp(TokenList[0], L"default_selection") == 0) { + HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); + + } else if (StriCmp(TokenList[0], L"textonly") == 0) { + GlobalConfig.TextOnly = TRUE; + + } else if ((StriCmp(TokenList[0], L"}") == 0) || (StriCmp(TokenList[0], L"loader") == 0) || + (StriCmp(TokenList[0], L"icon") == 0) || (StriCmp(TokenList[0], L"options") == 0)) { + // Do nothing; handled by ScanUserConfigured() + } + + FreeTokenLine(&TokenList, &TokenCount); + } + + FreePool(File.Buffer); +} /* VOID ReadConfig() */ + +static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { + REFIT_MENU_SCREEN *SubScreen; + LOADER_ENTRY *SubEntry; + UINTN TokenCount; + CHAR16 **TokenList; + + SubScreen = InitializeSubScreen(Entry); + + // Set defaults for the new entry; will be modified based on lines read from the config. file.... + SubEntry = InitializeLoaderEntry(Entry); + + if ((SubEntry == NULL) || (SubScreen == NULL)) + return; + SubEntry->me.Title = StrDuplicate(Title); + + while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StriCmp(TokenList[0], L"}") != 0)) { + if ((StriCmp(TokenList[0], L"loader") == 0) && (TokenCount > 1)) { // set the boot loader filename + if (SubEntry->LoaderPath != NULL) + FreePool(SubEntry->LoaderPath); + SubEntry->LoaderPath = StrDuplicate(TokenList[1]); + SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + } else if (StriCmp(TokenList[0], L"initrd") == 0) { + if (SubEntry->InitrdPath != NULL) + FreePool(SubEntry->InitrdPath); + SubEntry->InitrdPath = NULL; + if (TokenCount > 1) { + SubEntry->InitrdPath = StrDuplicate(TokenList[1]); + } + } else if (StriCmp(TokenList[0], L"options") == 0) { + if (SubEntry->LoadOptions != NULL) + FreePool(SubEntry->LoadOptions); + SubEntry->LoadOptions = NULL; + if (TokenCount > 1) { + SubEntry->LoadOptions = StrDuplicate(TokenList[1]); + } // if/else + } else if ((StriCmp(TokenList[0], L"add_options") == 0) && (TokenCount > 1)) { + MergeStrings(&SubEntry->LoadOptions, TokenList[1], L' '); + } else if ((StriCmp(TokenList[0], L"graphics") == 0) && (TokenCount > 1)) { + SubEntry->UseGraphicsMode = (StriCmp(TokenList[1], L"on") == 0); + } else if (StriCmp(TokenList[0], L"disabled") == 0) { + SubEntry->Enabled = FALSE; + } // ief/elseif + FreeTokenLine(&TokenList, &TokenCount); + } // while() + if (SubEntry->InitrdPath != NULL) { + MergeStrings(&SubEntry->LoadOptions, L"initrd=", L' '); + MergeStrings(&SubEntry->LoadOptions, SubEntry->InitrdPath, 0); + FreePool(SubEntry->InitrdPath); + SubEntry->InitrdPath = NULL; + } // if + if (SubEntry->Enabled == TRUE) { + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + Entry->me.SubScreen = SubScreen; +} // VOID AddSubmenu() + +// Adds the options from a SINGLE loaders.conf stanza to a new loader entry and returns +// that entry. The calling function is then responsible for adding the entry to the +// list of entries. +static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { + CHAR16 **TokenList; + UINTN TokenCount; + LOADER_ENTRY *Entry; + BOOLEAN DefaultsSet = FALSE, AddedSubmenu = FALSE; + + // prepare the menu entry + Entry = InitializeLoaderEntry(NULL); + if (Entry == NULL) + return NULL; + + Entry->Title = StrDuplicate(Title); + Entry->me.Title = PoolPrint(L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", Volume->VolName); + Entry->me.Row = 0; + Entry->me.BadgeImage = Volume->VolBadgeImage; + Entry->VolName = Volume->VolName; + + // Parse the config file to add options for a single stanza, terminating when the token + // is "}" or when the end of file is reached. + while (((TokenCount = ReadTokenLine(File, &TokenList)) > 0) && (StriCmp(TokenList[0], L"}") != 0)) { + if ((StriCmp(TokenList[0], L"loader") == 0) && (TokenCount > 1)) { // set the boot loader filename + Entry->LoaderPath = StrDuplicate(TokenList[1]); + Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath); + SetLoaderDefaults(Entry, TokenList[1], Volume); + FreePool(Entry->LoadOptions); + Entry->LoadOptions = NULL; // Discard default options, if any + DefaultsSet = TRUE; + } else if ((StriCmp(TokenList[0], L"icon") == 0) && (TokenCount > 1)) { + FreePool(Entry->me.Image); + Entry->me.Image = LoadIcns(Volume->RootDir, TokenList[1], 128); + if (Entry->me.Image == NULL) { + Entry->me.Image = DummyImage(128); + } + } else if ((StriCmp(TokenList[0], L"initrd") == 0) && (TokenCount > 1)) { + if (Entry->InitrdPath) + FreePool(Entry->InitrdPath); + Entry->InitrdPath = StrDuplicate(TokenList[1]); + } else if ((StriCmp(TokenList[0], L"options") == 0) && (TokenCount > 1)) { + if (Entry->LoadOptions) + FreePool(Entry->LoadOptions); + Entry->LoadOptions = StrDuplicate(TokenList[1]); + } else if ((StriCmp(TokenList[0], L"ostype") == 0) && (TokenCount > 1)) { + if (TokenCount > 1) { + Entry->OSType = TokenList[1][0]; + } + } else if ((StriCmp(TokenList[0], L"graphics") == 0) && (TokenCount > 1)) { + Entry->UseGraphicsMode = (StriCmp(TokenList[1], L"on") == 0); + } else if (StriCmp(TokenList[0], L"disabled") == 0) { + Entry->Enabled = FALSE; + } else if ((StriCmp(TokenList[0], L"submenuentry") == 0) && (TokenCount > 1)) { + AddSubmenu(Entry, File, Volume, TokenList[1]); + AddedSubmenu = TRUE; + } // set options to pass to the loader program + FreeTokenLine(&TokenList, &TokenCount); + } // while() + + if (AddedSubmenu) + AddMenuEntry(Entry->me.SubScreen, &MenuEntryReturn); + + if (Entry->InitrdPath) { + MergeStrings(&Entry->LoadOptions, L"initrd=", L' '); + MergeStrings(&Entry->LoadOptions, Entry->InitrdPath, 0); + FreePool(Entry->InitrdPath); + Entry->InitrdPath = NULL; + } // if + + if (!DefaultsSet) + SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", Volume); // user included no entry; use bogus one + + return(Entry); +} // static VOID AddStanzaEntries() + +// Read the user-configured loaders file, loaders.conf, and add or delete +// entries based on the contents of that file.... +VOID ScanUserConfigured(VOID) +{ + EFI_STATUS Status; + REFIT_FILE File; + REFIT_VOLUME *Volume; + CHAR16 **TokenList; + CHAR16 *Title = NULL; + UINTN TokenCount; + LOADER_ENTRY *Entry; + + if (FileExists(SelfDir, CONFIG_FILE_NAME)) { + Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File); + if (EFI_ERROR(Status)) + return; + + Volume = SelfVolume; + // TODO: Figure out how to set volumes (on per-image basis, preferably) + + while ((TokenCount = ReadTokenLine(&File, &TokenList)) > 0) { + if ((StriCmp(TokenList[0], L"menuentry") == 0) && (TokenCount > 1)) { + Title = StrDuplicate(TokenList[1]); + Entry = AddStanzaEntries(&File, Volume, TokenList[1]); + if (Entry->Enabled) { + if (Entry->me.SubScreen == NULL) + GenerateSubScreen(Entry, Volume); + AddPreparedLoaderEntry(Entry); + } else { + FreePool(Entry); + } // if/else + FreePool(Title); + } // if + FreeTokenLine(&TokenList, &TokenCount); + } // while() + } // if() +} // VOID ScanUserConfigured() + +// Read a Linux kernel options file for a Linux boot loader into memory. The LoaderPath +// and Volume variables identify the location of the options file, but not its name -- +// you pass this function the filename of the Linux kernel, initial RAM disk, or other +// file in the target directory, and this function finds the file with the name +// LINUX_OPTIONS_FILENAME within that directory and loads it. +// The return value is a pointer to the REFIT_FILE handle for the file, or NULL if +// it wasn't found. +REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 *OptionsFilename = NULL; + REFIT_FILE *File = NULL; + EFI_STATUS Status; + + OptionsFilename = FindPath(LoaderPath); + MergeStrings(&OptionsFilename, LINUX_OPTIONS_FILENAME, L'\\'); + if (FileExists(Volume->RootDir, OptionsFilename)) { + File = AllocateZeroPool(sizeof(REFIT_FILE)); + Status = ReadFile(Volume->RootDir, OptionsFilename, File); + if (CheckError(Status, L"while loading the Linux options file")) + File = NULL; + } + if (OptionsFilename != NULL) + FreePool(OptionsFilename); + return (File); +} // static REFIT_FILE * FindLinuxOptionsFile() + +// Retrieve a single line of options from a Linux kernel options file +CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + UINTN TokenCount; + CHAR16 *Options = NULL; + CHAR16 **TokenList; + REFIT_FILE *File; + + File = ReadLinuxOptionsFile(LoaderPath, Volume); + if (File != NULL) { + TokenCount = ReadTokenLine(File, &TokenList); + if (TokenCount > 1) + Options = StrDuplicate(TokenList[1]); + FreeTokenLine(&TokenList, &TokenCount); + FreePool(File); + } + return Options; +} // static CHAR16 * GetOptionsFile() + diff --git a/refind/config.h b/refind/config.h new file mode 100644 index 0000000..6e32ea8 --- /dev/null +++ b/refind/config.h @@ -0,0 +1,86 @@ +/* + * refit/config.h + * General header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +#include "efi.h" +#include "global.h" + +// +// config module +// + +typedef struct { + UINT8 *Buffer; + UINTN BufferSize; + UINTN Encoding; + CHAR8 *Current8Ptr; + CHAR8 *End8Ptr; + CHAR16 *Current16Ptr; + CHAR16 *End16Ptr; +} REFIT_FILE; + +#define DISABLE_FLAG_SHELL (0x0001) +#define DISABLE_FLAG_TOOLS (0x0002) +#define DISABLE_FLAG_SINGLEUSER (0x0004) +#define DISABLE_FLAG_HWTEST (0x0008) +#define DISABLE_ALL ((0xffff)) + +#define HIDEUI_FLAG_BANNER (0x0001) +#define HIDEUI_FLAG_FUNCS (0x0002) +#define HIDEUI_FLAG_LABEL (0x0004) +#define HIDEUI_ALL (0xffff) + +VOID ReadConfig(VOID); +VOID ScanUserConfigured(VOID); +UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList); +VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount); +REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); +CHAR16 * GetFirstOptionsFromFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); + +#endif + +/* EOF */ diff --git a/refind/global.h b/refind/global.h new file mode 100644 index 0000000..dccac51 --- /dev/null +++ b/refind/global.h @@ -0,0 +1,182 @@ +/* + * refit/global.h + * Global header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __GLOBAL_H_ +#define __GLOBAL_H_ + +#include "efi.h" +#include "efilib.h" + +#include "libeg.h" + +#define REFIT_DEBUG (0) + +#define TAG_ABOUT (1) +#define TAG_RESET (2) +#define TAG_SHUTDOWN (3) +#define TAG_TOOL (4) +#define TAG_LOADER (5) +#define TAG_LEGACY (6) + +#define NUM_SCAN_OPTIONS 10 + +// +// global definitions +// + +// global types + +typedef struct { + UINT8 Flags; + UINT8 StartCHS1; + UINT8 StartCHS2; + UINT8 StartCHS3; + UINT8 Type; + UINT8 EndCHS1; + UINT8 EndCHS2; + UINT8 EndCHS3; + UINT32 StartLBA; + UINT32 Size; +} MBR_PARTITION_INFO; + +typedef struct { + EFI_DEVICE_PATH *DevicePath; + EFI_HANDLE DeviceHandle; + EFI_FILE *RootDir; + CHAR16 *VolName; + EG_IMAGE *VolBadgeImage; + UINTN DiskKind; + BOOLEAN IsAppleLegacy; + BOOLEAN HasBootCode; + CHAR16 *OSIconName; + CHAR16 *OSName; + BOOLEAN IsMbrPartition; + UINTN MbrPartitionIndex; + EFI_BLOCK_IO *BlockIO; + UINT64 BlockIOOffset; + EFI_BLOCK_IO *WholeDiskBlockIO; + EFI_DEVICE_PATH *WholeDiskDevicePath; + MBR_PARTITION_INFO *MbrPartitionTable; +} REFIT_VOLUME; + +typedef struct _refit_menu_entry { + CHAR16 *Title; + UINTN Tag; + UINTN Row; + CHAR16 ShortcutDigit; + CHAR16 ShortcutLetter; + EG_IMAGE *Image; + EG_IMAGE *BadgeImage; + struct _refit_menu_screen *SubScreen; +} REFIT_MENU_ENTRY; + +typedef struct _refit_menu_screen { + CHAR16 *Title; + EG_IMAGE *TitleImage; + UINTN InfoLineCount; + CHAR16 **InfoLines; + UINTN EntryCount; // total number of entries registered + REFIT_MENU_ENTRY **Entries; + UINTN TimeoutSeconds; + CHAR16 *TimeoutText; +} REFIT_MENU_SCREEN; + +typedef struct { + REFIT_MENU_ENTRY me; + CHAR16 *Title; + CHAR16 *LoaderPath; + CHAR16 *VolName; + EFI_DEVICE_PATH *DevicePath; + BOOLEAN UseGraphicsMode; + BOOLEAN Enabled; + CHAR16 *LoadOptions; + CHAR16 *InitrdPath; // Linux stub loader only + CHAR8 OSType; +} LOADER_ENTRY; + +typedef struct { + REFIT_MENU_ENTRY me; + REFIT_VOLUME *Volume; + CHAR16 *LoadOptions; + BOOLEAN Enabled; +} LEGACY_ENTRY; + +typedef struct { + BOOLEAN TextOnly; + UINTN Timeout; + UINTN DisableFlags; + UINTN HideUIFlags; + BOOLEAN Quiet; + CHAR16 *BannerFileName; + CHAR16 *SelectionSmallFileName; + CHAR16 *SelectionBigFileName; + CHAR16 *DefaultSelection; + CHAR8 ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan +} REFIT_CONFIG; + +// Global variables + +extern EFI_HANDLE SelfImageHandle; +extern EFI_LOADED_IMAGE *SelfLoadedImage; +extern EFI_FILE *SelfRootDir; +extern EFI_FILE *SelfDir; +extern CHAR16 *SelfDirPath; + +extern REFIT_VOLUME *SelfVolume; +extern REFIT_VOLUME **Volumes; +extern UINTN VolumesCount; + +extern REFIT_CONFIG GlobalConfig; + +LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry); +REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry); +VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume); +LOADER_ENTRY * MakeGenericLoaderEntry(VOID); +LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume); +VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); +LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry); + +#endif + +/* EOF */ diff --git a/refind/icns.c b/refind/icns.c new file mode 100644 index 0000000..54a3ea7 --- /dev/null +++ b/refind/icns.c @@ -0,0 +1,187 @@ +/* + * refit/icns.c + * Loader for .icns icon files + * + * Copyright (c) 2006-2007 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "global.h" +#include "lib.h" +#include "icns.h" +#include "config.h" + +// +// well-known icons +// + +typedef struct { + EG_IMAGE *Image; + CHAR16 *Path; + UINTN PixelSize; +} BUILTIN_ICON; + +BUILTIN_ICON BuiltinIconTable[BUILTIN_ICON_COUNT] = { + { NULL, L"icons\\func_about.icns", 48 }, + { NULL, L"icons\\func_reset.icns", 48 }, + { NULL, L"icons\\func_shutdown.icns", 48 }, + { NULL, L"icons\\tool_shell.icns", 48 }, + { NULL, L"icons\\tool_part.icns", 48 }, + { NULL, L"icons\\tool_rescue.icns", 48 }, + { NULL, L"icons\\vol_internal.icns", 32 }, + { NULL, L"icons\\vol_external.icns", 32 }, + { NULL, L"icons\\vol_optical.icns", 32 }, +}; + +EG_IMAGE * BuiltinIcon(IN UINTN Id) +{ + if (Id >= BUILTIN_ICON_COUNT) + return NULL; + + if (BuiltinIconTable[Id].Image == NULL) + BuiltinIconTable[Id].Image = LoadIcnsFallback(SelfDir, BuiltinIconTable[Id].Path, BuiltinIconTable[Id].PixelSize); + + return BuiltinIconTable[Id].Image; +} + +// +// Load an icon for an operating system +// + +EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo) +{ + EG_IMAGE *Image; + CHAR16 CutoutName[16]; + CHAR16 FileName[256]; + UINTN StartIndex, Index, NextIndex; + + if (GlobalConfig.TextOnly) // skip loading if it's not used anyway + return NULL; + Image = NULL; + + // try the names from OSIconName + for (StartIndex = 0; OSIconName != NULL && OSIconName[StartIndex]; StartIndex = NextIndex) { + // find the next name in the list + NextIndex = 0; + for (Index = StartIndex; OSIconName[Index]; Index++) { + if (OSIconName[Index] == ',') { + NextIndex = Index + 1; + break; + } + } + if (OSIconName[Index] == 0) + NextIndex = Index; + + // construct full path + if (Index > StartIndex + 15) // prevent buffer overflow + continue; + CopyMem(CutoutName, OSIconName + StartIndex, (Index - StartIndex) * sizeof(CHAR16)); + CutoutName[Index - StartIndex] = 0; + SPrint(FileName, 255, L"icons\\%s_%s.icns", + BootLogo ? L"boot" : L"os", CutoutName); + + // try to load it + Image = egLoadIcon(SelfDir, FileName, 128); + if (Image != NULL) + return Image; + } + + // try the fallback name + SPrint(FileName, 255, L"icons\\%s_%s.icns", + BootLogo ? L"boot" : L"os", FallbackIconName); + Image = egLoadIcon(SelfDir, FileName, 128); + if (Image != NULL) + return Image; + + // try the fallback name with os_ instead of boot_ + if (BootLogo) + return LoadOSIcon(NULL, FallbackIconName, FALSE); + + return DummyImage(128); +} + +// +// Load an image from a .icns file +// + +EG_IMAGE * LoadIcns(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize) +{ + if (GlobalConfig.TextOnly) // skip loading if it's not used anyway + return NULL; + return egLoadIcon(BaseDir, FileName, PixelSize); +} + +static EG_PIXEL BlackPixel = { 0x00, 0x00, 0x00, 0 }; +//static EG_PIXEL YellowPixel = { 0x00, 0xff, 0xff, 0 }; + +EG_IMAGE * DummyImage(IN UINTN PixelSize) +{ + EG_IMAGE *Image; + UINTN x, y, LineOffset; + CHAR8 *Ptr, *YPtr; + + Image = egCreateFilledImage(PixelSize, PixelSize, TRUE, &BlackPixel); + + LineOffset = PixelSize * 4; + + YPtr = (CHAR8 *)Image->PixelData + ((PixelSize - 32) >> 1) * (LineOffset + 4); + for (y = 0; y < 32; y++) { + Ptr = YPtr; + for (x = 0; x < 32; x++) { + if (((x + y) % 12) < 6) { + *Ptr++ = 0; + *Ptr++ = 0; + *Ptr++ = 0; + } else { + *Ptr++ = 0; + *Ptr++ = 255; + *Ptr++ = 255; + } + *Ptr++ = 144; + } + YPtr += LineOffset; + } + + return Image; +} + +EG_IMAGE * LoadIcnsFallback(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize) +{ + EG_IMAGE *Image; + if (GlobalConfig.TextOnly) // skip loading if it's not used anyway + return NULL; + + Image = LoadIcns(BaseDir, FileName, PixelSize); + if (Image == NULL) { + Image = DummyImage(PixelSize); + } + return Image; +} diff --git a/refind/icns.h b/refind/icns.h new file mode 100644 index 0000000..eb3370c --- /dev/null +++ b/refind/icns.h @@ -0,0 +1,73 @@ +/* + * refit/icns.h + * Icon management header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __ICNS_H_ +#define __ICNS_H_ + +// +// icns loader module +// + +EG_IMAGE * LoadOSIcon(IN CHAR16 *OSIconName OPTIONAL, IN CHAR16 *FallbackIconName, BOOLEAN BootLogo); + +EG_IMAGE * LoadIcns(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize); +EG_IMAGE * LoadIcnsFallback(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN UINTN PixelSize); +EG_IMAGE * DummyImage(IN UINTN PixelSize); + +EG_IMAGE * BuiltinIcon(IN UINTN Id); + +#define BUILTIN_ICON_FUNC_ABOUT (0) +#define BUILTIN_ICON_FUNC_RESET (1) +#define BUILTIN_ICON_FUNC_SHUTDOWN (2) +#define BUILTIN_ICON_TOOL_SHELL (3) +#define BUILTIN_ICON_TOOL_PART (4) +#define BUILTIN_ICON_TOOL_RESCUE (5) +#define BUILTIN_ICON_VOL_INTERNAL (6) +#define BUILTIN_ICON_VOL_EXTERNAL (7) +#define BUILTIN_ICON_VOL_OPTICAL (8) +#define BUILTIN_ICON_COUNT (9) + +#endif + +/* EOF */ diff --git a/refind/lib.c b/refind/lib.c new file mode 100644 index 0000000..1e4be18 --- /dev/null +++ b/refind/lib.c @@ -0,0 +1,1129 @@ +/* + * refit/lib.c + * General library functions + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#include "global.h" +#include "lib.h" +#include "icns.h" +#include "screen.h" +#include "refit_call_wrapper.h" + +// variables + +EFI_HANDLE SelfImageHandle; +EFI_LOADED_IMAGE *SelfLoadedImage; +EFI_FILE *SelfRootDir; +EFI_FILE *SelfDir; +CHAR16 *SelfDirPath; + +REFIT_VOLUME *SelfVolume = NULL; +REFIT_VOLUME **Volumes = NULL; +UINTN VolumesCount = 0; + +// Maximum size for disk sectors +#define SECTOR_SIZE 4096 + +// functions + +static EFI_STATUS FinishInitRefitLib(VOID); + +static VOID UninitVolumes(VOID); + +// +// self recognition stuff +// + +EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle) +{ + EFI_STATUS Status; + CHAR16 *DevicePathAsString; + CHAR16 BaseDirectory[256]; + UINTN i; + + SelfImageHandle = ImageHandle; + Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage); + if (CheckFatalError(Status, L"while getting a LoadedImageProtocol handle")) + return EFI_LOAD_ERROR; + + // find the current directory + DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath); + if (DevicePathAsString != NULL) { + StrCpy(BaseDirectory, DevicePathAsString); + FreePool(DevicePathAsString); + for (i = StrLen(BaseDirectory); i > 0 && BaseDirectory[i] != '\\'; i--) ; + BaseDirectory[i] = 0; + } else + BaseDirectory[0] = 0; + SelfDirPath = StrDuplicate(BaseDirectory); + + return FinishInitRefitLib(); +} + +// called before running external programs to close open file handles +VOID UninitRefitLib(VOID) +{ + UninitVolumes(); + + if (SelfDir != NULL) { + refit_call1_wrapper(SelfDir->Close, SelfDir); + SelfDir = NULL; + } + + if (SelfRootDir != NULL) { + refit_call1_wrapper(SelfRootDir->Close, SelfRootDir); + SelfRootDir = NULL; + } +} + +// called after running external programs to re-open file handles +EFI_STATUS ReinitRefitLib(VOID) +{ + ReinitVolumes(); + + if (SelfVolume != NULL && SelfVolume->RootDir != NULL) + SelfRootDir = SelfVolume->RootDir; + + return FinishInitRefitLib(); +} + +static EFI_STATUS FinishInitRefitLib(VOID) +{ + EFI_STATUS Status; + + if (SelfRootDir == NULL) { + SelfRootDir = LibOpenRoot(SelfLoadedImage->DeviceHandle); + if (SelfRootDir == NULL) { + CheckError(EFI_LOAD_ERROR, L"while (re)opening our installation volume"); + return EFI_LOAD_ERROR; + } + } + + Status = refit_call5_wrapper(SelfRootDir->Open, SelfRootDir, &SelfDir, SelfDirPath, EFI_FILE_MODE_READ, 0); + if (CheckFatalError(Status, L"while opening our installation directory")) + return EFI_LOAD_ERROR; + + return EFI_SUCCESS; +} + +// +// list functions +// + +VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount) +{ + UINTN AllocateCount; + + *ElementCount = InitialElementCount; + if (*ElementCount > 0) { + AllocateCount = (*ElementCount + 7) & ~7; // next multiple of 8 + *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); + } else { + *ListPtr = NULL; + } +} + +VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement) +{ + UINTN AllocateCount; + + if ((*ElementCount & 7) == 0) { + AllocateCount = *ElementCount + 8; + if (*ElementCount == 0) + *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); + else + *ListPtr = ReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount); + } + (*ListPtr)[*ElementCount] = NewElement; + (*ElementCount)++; +} /* VOID AddListElement() */ + +VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount) +{ + UINTN i; + + if (*ElementCount > 0) { + for (i = 0; i < *ElementCount; i++) { + // TODO: call a user-provided routine for each element here + FreePool((*ListPtr)[i]); + } + FreePool(*ListPtr); + } +} + +// +// firmware device path discovery +// + +static UINT8 LegacyLoaderMediaPathData[] = { + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +static EFI_DEVICE_PATH *LegacyLoaderMediaPath = (EFI_DEVICE_PATH *)LegacyLoaderMediaPathData; + +VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList) +{ + EFI_STATUS Status; + UINTN HandleCount = 0; + UINTN HandleIndex, HardcodedIndex; + EFI_HANDLE *Handles; + EFI_HANDLE Handle; + UINTN PathCount = 0; + UINTN PathIndex; + EFI_LOADED_IMAGE *LoadedImage; + EFI_DEVICE_PATH *DevicePath; + BOOLEAN Seen; + + MaxPaths--; // leave space for the terminating NULL pointer + + // get all LoadedImage handles + Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, + &HandleCount, &Handles); + if (CheckError(Status, L"while listing LoadedImage handles")) { + if (HardcodedPathList) { + for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) + PathList[PathCount++] = HardcodedPathList[HardcodedIndex]; + } + PathList[PathCount] = NULL; + return; + } + for (HandleIndex = 0; HandleIndex < HandleCount && PathCount < MaxPaths; HandleIndex++) { + Handle = Handles[HandleIndex]; + + Status = refit_call3_wrapper(BS->HandleProtocol, Handle, &LoadedImageProtocol, (VOID **) &LoadedImage); + if (EFI_ERROR(Status)) + continue; // This can only happen if the firmware scewed up, ignore it. + + Status = refit_call3_wrapper(BS->HandleProtocol, LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID **) &DevicePath); + if (EFI_ERROR(Status)) + continue; // This happens, ignore it. + + // Only grab memory range nodes + if (DevicePathType(DevicePath) != HARDWARE_DEVICE_PATH || DevicePathSubType(DevicePath) != HW_MEMMAP_DP) + continue; + + // Check if we have this device path in the list already + // WARNING: This assumes the first node in the device path is unique! + Seen = FALSE; + for (PathIndex = 0; PathIndex < PathCount; PathIndex++) { + if (DevicePathNodeLength(DevicePath) != DevicePathNodeLength(PathList[PathIndex])) + continue; + if (CompareMem(DevicePath, PathList[PathIndex], DevicePathNodeLength(DevicePath)) == 0) { + Seen = TRUE; + break; + } + } + if (Seen) + continue; + + PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath); + } + FreePool(Handles); + + if (HardcodedPathList) { + for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) + PathList[PathCount++] = HardcodedPathList[HardcodedIndex]; + } + PathList[PathCount] = NULL; +} + +// +// volume functions +// + +static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootable) +{ + EFI_STATUS Status; + UINT8 SectorBuffer[SECTOR_SIZE]; + UINTN i; + MBR_PARTITION_INFO *MbrTable; + BOOLEAN MbrTableFound; + + Volume->HasBootCode = FALSE; + Volume->OSIconName = NULL; + Volume->OSName = NULL; + *Bootable = FALSE; + + if (Volume->BlockIO == NULL) + return; + if (Volume->BlockIO->Media->BlockSize > SECTOR_SIZE) + return; // our buffer is too small... + + // look at the boot sector (this is used for both hard disks and El Torito images!) + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, + Volume->BlockIO, Volume->BlockIO->Media->MediaId, + Volume->BlockIOOffset, SECTOR_SIZE, SectorBuffer); + if (!EFI_ERROR(Status)) { + + if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55 && SectorBuffer[0] != 0) { + *Bootable = TRUE; + Volume->HasBootCode = TRUE; + } + + // detect specific boot codes + if (CompareMem(SectorBuffer + 2, "LILO", 4) == 0 || + CompareMem(SectorBuffer + 6, "LILO", 4) == 0 || + CompareMem(SectorBuffer + 3, "SYSLINUX", 8) == 0 || + FindMem(SectorBuffer, SECTOR_SIZE, "ISOLINUX", 8) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"linux"; + Volume->OSName = L"Linux"; + + } else if (FindMem(SectorBuffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { // GRUB + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"grub,linux"; + Volume->OSName = L"Linux"; + + } else if ((*((UINT32 *)(SectorBuffer + 502)) == 0 && + *((UINT32 *)(SectorBuffer + 506)) == 50000 && + *((UINT16 *)(SectorBuffer + 510)) == 0xaa55) || + FindMem(SectorBuffer, SECTOR_SIZE, "Starting the BTX loader", 23) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"freebsd"; + Volume->OSName = L"FreeBSD"; + + } else if (FindMem(SectorBuffer, 512, "!Loading", 8) >= 0 || + FindMem(SectorBuffer, SECTOR_SIZE, "/cdboot\0/CDBOOT\0", 16) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"openbsd"; + Volume->OSName = L"OpenBSD"; + + } else if (FindMem(SectorBuffer, 512, "Not a bootxx image", 18) >= 0 || + *((UINT32 *)(SectorBuffer + 1028)) == 0x7886b6d1) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"netbsd"; + Volume->OSName = L"NetBSD"; + + } else if (FindMem(SectorBuffer, SECTOR_SIZE, "NTLDR", 5) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"win"; + Volume->OSName = L"Windows"; + + } else if (FindMem(SectorBuffer, SECTOR_SIZE, "BOOTMGR", 7) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"winvista,win"; + Volume->OSName = L"Windows"; + + } else if (FindMem(SectorBuffer, 512, "CPUBOOT SYS", 11) >= 0 || + FindMem(SectorBuffer, 512, "KERNEL SYS", 11) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"freedos"; + Volume->OSName = L"FreeDOS"; + + } else if (FindMem(SectorBuffer, 512, "OS2LDR", 6) >= 0 || + FindMem(SectorBuffer, 512, "OS2BOOT", 7) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"ecomstation"; + Volume->OSName = L"eComStation"; + + } else if (FindMem(SectorBuffer, 512, "Be Boot Loader", 14) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"beos"; + Volume->OSName = L"BeOS"; + + } else if (FindMem(SectorBuffer, 512, "yT Boot Loader", 14) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"zeta,beos"; + Volume->OSName = L"ZETA"; + + } else if (FindMem(SectorBuffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 || + FindMem(SectorBuffer, 512, "\x06" "system\x0c" "haiku_loader", 20) >= 0) { + Volume->HasBootCode = TRUE; + Volume->OSIconName = L"haiku,beos"; + Volume->OSName = L"Haiku"; + + } + + // NOTE: If you add an operating system with a name that starts with 'W' or 'L', you + // need to fix AddLegacyEntry in main.c. + +#if REFIT_DEBUG > 0 + Print(L" Result of bootcode detection: %s %s (%s)\n", + Volume->HasBootCode ? L"bootable" : L"non-bootable", + Volume->OSName, Volume->OSIconName); +#endif + + if (FindMem(SectorBuffer, 512, "Non-system disk", 15) >= 0) // dummy FAT boot sector + Volume->HasBootCode = FALSE; + + // check for MBR partition table + if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55) { + MbrTableFound = FALSE; + MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + for (i = 0; i < 4; i++) + if (MbrTable[i].StartLBA && MbrTable[i].Size) + MbrTableFound = TRUE; + for (i = 0; i < 4; i++) + if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80) + MbrTableFound = FALSE; + if (MbrTableFound) { + Volume->MbrPartitionTable = AllocatePool(4 * 16); + CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16); + } + } + + } else { +#if REFIT_DEBUG > 0 + CheckError(Status, L"while reading boot sector"); +#endif + } +} + +// default volume icon based on disk kind +static VOID ScanVolumeDefaultIcon(IN OUT REFIT_VOLUME *Volume) +{ + switch (Volume->DiskKind) { + case DISK_KIND_INTERNAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_INTERNAL); + break; + case DISK_KIND_EXTERNAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_EXTERNAL); + break; + case DISK_KIND_OPTICAL: + Volume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_OPTICAL); + break; + } // switch() +} + +static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH *DevicePath, *NextDevicePath; + EFI_DEVICE_PATH *DiskDevicePath, *RemainingDevicePath; + EFI_HANDLE WholeDiskHandle; + UINTN PartialLength; + EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr; + BOOLEAN Bootable; + + // get device path + Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle)); +#if REFIT_DEBUG > 0 + if (Volume->DevicePath != NULL) { + Print(L"* %s\n", DevicePathToStr(Volume->DevicePath)); +#if REFIT_DEBUG >= 2 + DumpHex(1, 0, DevicePathSize(Volume->DevicePath), Volume->DevicePath); +#endif + } +#endif + + Volume->DiskKind = DISK_KIND_INTERNAL; // default + + // get block i/o + Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); + if (EFI_ERROR(Status)) { + Volume->BlockIO = NULL; + Print(L"Warning: Can't get BlockIO protocol.\n"); + } else { + if (Volume->BlockIO->Media->BlockSize == 2048) + Volume->DiskKind = DISK_KIND_OPTICAL; + } + + // scan for bootcode and MBR table + Bootable = FALSE; + ScanVolumeBootcode(Volume, &Bootable); + + // detect device type + DevicePath = Volume->DevicePath; + while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { + NextDevicePath = NextDevicePathNode(DevicePath); + + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && + (DevicePathSubType(DevicePath) == MSG_USB_DP || + DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || + DevicePathSubType(DevicePath) == MSG_1394_DP || + DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP)) + Volume->DiskKind = DISK_KIND_EXTERNAL; // USB/FireWire/FC device -> external + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && + DevicePathSubType(DevicePath) == MEDIA_CDROM_DP) { + Volume->DiskKind = DISK_KIND_OPTICAL; // El Torito entry -> optical disk + Bootable = TRUE; + } + + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) { + Volume->IsAppleLegacy = TRUE; // legacy BIOS device entry + // TODO: also check for Boot Camp GUID + Bootable = FALSE; // this handle's BlockIO is just an alias for the whole device + } + + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH) { + // make a device path for the whole device + PartialLength = (UINT8 *)NextDevicePath - (UINT8 *)(Volume->DevicePath); + DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH)); + CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength); + CopyMem((UINT8 *)DiskDevicePath + PartialLength, EndDevicePath, sizeof(EFI_DEVICE_PATH)); + + // get the handle for that path + RemainingDevicePath = DiskDevicePath; + //Print(L" * looking at %s\n", DevicePathToStr(RemainingDevicePath)); + Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); + //Print(L" * remaining: %s\n", DevicePathToStr(RemainingDevicePath)); + FreePool(DiskDevicePath); + + if (!EFI_ERROR(Status)) { + //Print(L" - original handle: %08x - disk handle: %08x\n", (UINT32)DeviceHandle, (UINT32)WholeDiskHandle); + + // get the device path for later + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &DevicePathProtocol, (VOID **) &DiskDevicePath); + if (!EFI_ERROR(Status)) { + Volume->WholeDiskDevicePath = DuplicateDevicePath(DiskDevicePath); + } + + // look at the BlockIO protocol + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO); + if (!EFI_ERROR(Status)) { + + // check the media block size + if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048) + Volume->DiskKind = DISK_KIND_OPTICAL; + + } else { + Volume->WholeDiskBlockIO = NULL; + //CheckError(Status, L"from HandleProtocol"); + } + } //else + // CheckError(Status, L"from LocateDevicePath"); + } + + DevicePath = NextDevicePath; + } // while + + if (!Bootable) { +#if REFIT_DEBUG > 0 + if (Volume->HasBootCode) + Print(L" Volume considered non-bootable, but boot code is present\n"); +#endif + Volume->HasBootCode = FALSE; + } + + // default volume icon based on disk kind + ScanVolumeDefaultIcon(Volume); + + // open the root directory of the volume + Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); + if (Volume->RootDir == NULL) { + return; + } + + // get volume name + FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); + if (FileSystemInfoPtr != NULL) { + Volume->VolName = StrDuplicate(FileSystemInfoPtr->VolumeLabel); + FreePool(FileSystemInfoPtr); + } + + // TODO: if no official volume name is found or it is empty, use something else, e.g.: + // - name from bytes 3 to 10 of the boot sector + // - partition number + // - name derived from file system type or partition type + + // get custom volume icon if present + if (FileExists(Volume->RootDir, L".VolumeIcon.icns")) + Volume->VolBadgeImage = LoadIcns(Volume->RootDir, L".VolumeIcon.icns", 32); +} + +static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) +{ + EFI_STATUS Status; + REFIT_VOLUME *Volume; + UINT32 ExtBase, ExtCurrent, NextExtCurrent; + UINTN i; + UINTN LogicalPartitionIndex = 4; + UINT8 SectorBuffer[512]; + BOOLEAN Bootable; + MBR_PARTITION_INFO *EMbrTable; + + ExtBase = MbrEntry->StartLBA; + + for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { + // read current EMBR + Status = refit_call5_wrapper(WholeDiskVolume->BlockIO->ReadBlocks, + WholeDiskVolume->BlockIO, + WholeDiskVolume->BlockIO->Media->MediaId, + ExtCurrent, 512, SectorBuffer); + if (EFI_ERROR(Status)) + break; + if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) + break; + EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + + // scan logical partitions in this EMBR + NextExtCurrent = 0; + for (i = 0; i < 4; i++) { + if ((EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) || + EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0) + break; + if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) { + // set next ExtCurrent + NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; + break; + } else { + + // found a logical partition + Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); + Volume->DiskKind = WholeDiskVolume->DiskKind; + Volume->IsMbrPartition = TRUE; + Volume->MbrPartitionIndex = LogicalPartitionIndex++; + Volume->VolName = PoolPrint(L"Partition %d", Volume->MbrPartitionIndex + 1); + Volume->BlockIO = WholeDiskVolume->BlockIO; + Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA; + Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO; + + Bootable = FALSE; + ScanVolumeBootcode(Volume, &Bootable); + if (!Bootable) + Volume->HasBootCode = FALSE; + + ScanVolumeDefaultIcon(Volume); + + AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); + + } + } + } +} + +VOID ScanVolumes(VOID) +{ + EFI_STATUS Status; + UINTN HandleCount = 0; + UINTN HandleIndex; + EFI_HANDLE *Handles; + REFIT_VOLUME *Volume, *WholeDiskVolume; + UINTN VolumeIndex, VolumeIndex2; + MBR_PARTITION_INFO *MbrTable; + UINTN PartitionIndex; + UINT8 *SectorBuffer1, *SectorBuffer2; + UINTN SectorSum, i; + + FreePool(Volumes); + Volumes = NULL; + VolumesCount = 0; + + // get all filesystem handles + Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles); + // was: &FileSystemProtocol + if (Status == EFI_NOT_FOUND) + return; // no filesystems. strange, but true... + if (CheckError(Status, L"while listing all file systems")) + return; + + // first pass: collect information about all handles + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); + Volume->DeviceHandle = Handles[HandleIndex]; + ScanVolume(Volume); + + AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); + + if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) + SelfVolume = Volume; + } + FreePool(Handles); + + if (SelfVolume == NULL) + Print(L"WARNING: SelfVolume not found"); + + // second pass: relate partitions and whole disk devices + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + // check MBR partition table for extended partitions + if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL && + Volume->BlockIO == Volume->WholeDiskBlockIO && Volume->BlockIOOffset == 0 && + Volume->MbrPartitionTable != NULL) { + MbrTable = Volume->MbrPartitionTable; + for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) { + if (IS_EXTENDED_PART_TYPE(MbrTable[PartitionIndex].Type)) { + ScanExtendedPartition(Volume, MbrTable + PartitionIndex); + } + } + } + + // search for corresponding whole disk volume entry + WholeDiskVolume = NULL; + if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL && + Volume->BlockIO != Volume->WholeDiskBlockIO) { + for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { + if (Volumes[VolumeIndex2]->BlockIO == Volume->WholeDiskBlockIO && + Volumes[VolumeIndex2]->BlockIOOffset == 0) + WholeDiskVolume = Volumes[VolumeIndex2]; + } + } + + if (WholeDiskVolume != NULL && WholeDiskVolume->MbrPartitionTable != NULL) { + // check if this volume is one of the partitions in the table + MbrTable = WholeDiskVolume->MbrPartitionTable; + SectorBuffer1 = AllocatePool(512); + SectorBuffer2 = AllocatePool(512); + for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) { + // check size + if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1) + continue; + + // compare boot sector read through offset vs. directly + Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, + Volume->BlockIO, Volume->BlockIO->Media->MediaId, + Volume->BlockIOOffset, 512, SectorBuffer1); + if (EFI_ERROR(Status)) + break; + Status = refit_call5_wrapper(Volume->WholeDiskBlockIO->ReadBlocks, + Volume->WholeDiskBlockIO, Volume->WholeDiskBlockIO->Media->MediaId, + MbrTable[PartitionIndex].StartLBA, 512, SectorBuffer2); + if (EFI_ERROR(Status)) + break; + if (CompareMem(SectorBuffer1, SectorBuffer2, 512) != 0) + continue; + SectorSum = 0; + for (i = 0; i < 512; i++) + SectorSum += SectorBuffer1[i]; + if (SectorSum < 1000) + continue; + + // TODO: mark entry as non-bootable if it is an extended partition + + // now we're reasonably sure the association is correct... + Volume->IsMbrPartition = TRUE; + Volume->MbrPartitionIndex = PartitionIndex; + if (Volume->VolName == NULL) + Volume->VolName = PoolPrint(L"Partition %d", PartitionIndex + 1); + break; + } + + FreePool(SectorBuffer1); + FreePool(SectorBuffer2); + } + + } +} /* VOID ScanVolumes() */ + +static VOID UninitVolumes(VOID) +{ + REFIT_VOLUME *Volume; + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + + if (Volume->RootDir != NULL) { + refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir); + Volume->RootDir = NULL; + } + + Volume->DeviceHandle = NULL; + Volume->BlockIO = NULL; + Volume->WholeDiskBlockIO = NULL; + } +} + +VOID ReinitVolumes(VOID) +{ + EFI_STATUS Status; + REFIT_VOLUME *Volume; + UINTN VolumeIndex; + EFI_DEVICE_PATH *RemainingDevicePath; + EFI_HANDLE DeviceHandle, WholeDiskHandle; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + + if (Volume->DevicePath != NULL) { + // get the handle for that path + RemainingDevicePath = Volume->DevicePath; + Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle); + + if (!EFI_ERROR(Status)) { + Volume->DeviceHandle = DeviceHandle; + + // get the root directory + Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); + + } else + CheckError(Status, L"from LocateDevicePath"); + } + + if (Volume->WholeDiskDevicePath != NULL) { + // get the handle for that path + RemainingDevicePath = Volume->WholeDiskDevicePath; + Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); + + if (!EFI_ERROR(Status)) { + // get the BlockIO protocol + Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO); + if (EFI_ERROR(Status)) { + Volume->WholeDiskBlockIO = NULL; + CheckError(Status, L"from HandleProtocol"); + } + } else + CheckError(Status, L"from LocateDevicePath"); + } + } +} + +// +// file and dir functions +// + +BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE TestFile; + + Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0); + if (Status == EFI_SUCCESS) { + refit_call1_wrapper(TestFile->Close, TestFile); + return TRUE; + } + return FALSE; +} + +EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode) +{ + EFI_STATUS Status; + VOID *Buffer; + UINTN LastBufferSize, BufferSize; + INTN IterCount; + + for (;;) { + + // free pointer from last call + if (*DirEntry != NULL) { + FreePool(*DirEntry); + *DirEntry = NULL; + } + + // read next directory entry + LastBufferSize = BufferSize = 256; + Buffer = AllocatePool(BufferSize); + for (IterCount = 0; ; IterCount++) { + Status = refit_call3_wrapper(Directory->Read, Directory, &BufferSize, Buffer); + if (Status != EFI_BUFFER_TOO_SMALL || IterCount >= 4) + break; + if (BufferSize <= LastBufferSize) { + Print(L"FS Driver requests bad buffer size %d (was %d), using %d instead\n", BufferSize, LastBufferSize, LastBufferSize * 2); + BufferSize = LastBufferSize * 2; +#if REFIT_DEBUG > 0 + } else { + Print(L"Reallocating buffer from %d to %d\n", LastBufferSize, BufferSize); +#endif + } + Buffer = ReallocatePool(Buffer, LastBufferSize, BufferSize); + LastBufferSize = BufferSize; + } + if (EFI_ERROR(Status)) { + FreePool(Buffer); + break; + } + + // check for end of listing + if (BufferSize == 0) { // end of directory listing + FreePool(Buffer); + break; + } + + // entry is ready to be returned + *DirEntry = (EFI_FILE_INFO *)Buffer; + + // filter results + if (FilterMode == 1) { // only return directories + if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY)) + break; + } else if (FilterMode == 2) { // only return files + if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY) == 0) + break; + } else // no filter or unknown filter -> return everything + break; + + } + return Status; +} + +VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter) +{ + if (RelativePath == NULL) { + DirIter->LastStatus = EFI_SUCCESS; + DirIter->DirHandle = BaseDir; + DirIter->CloseDirHandle = FALSE; + } else { + DirIter->LastStatus = refit_call5_wrapper(BaseDir->Open, BaseDir, &(DirIter->DirHandle), RelativePath, EFI_FILE_MODE_READ, 0); + DirIter->CloseDirHandle = EFI_ERROR(DirIter->LastStatus) ? FALSE : TRUE; + } + DirIter->LastFileInfo = NULL; +} + +BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, + OUT EFI_FILE_INFO **DirEntry) +{ + if (DirIter->LastFileInfo != NULL) { + FreePool(DirIter->LastFileInfo); + DirIter->LastFileInfo = NULL; + } + + if (EFI_ERROR(DirIter->LastStatus)) + return FALSE; // stop iteration + + for (;;) { + DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode); + if (EFI_ERROR(DirIter->LastStatus)) + return FALSE; + if (DirIter->LastFileInfo == NULL) // end of listing + return FALSE; + if (FilePattern != NULL) { + if ((DirIter->LastFileInfo->Attribute & EFI_FILE_DIRECTORY)) + break; + if (MetaiMatch(DirIter->LastFileInfo->FileName, FilePattern)) + break; + // else continue loop + } else + break; + } + + *DirEntry = DirIter->LastFileInfo; + return TRUE; +} + +EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter) +{ + if (DirIter->LastFileInfo != NULL) { + FreePool(DirIter->LastFileInfo); + DirIter->LastFileInfo = NULL; + } + if (DirIter->CloseDirHandle) + refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle); + return DirIter->LastStatus; +} + +// +// file name manipulation +// + +// Returns the filename portion (minus path name) of the +// specified file +CHAR16 * Basename(IN CHAR16 *Path) +{ + CHAR16 *FileName; + UINTN i; + + FileName = Path; + + if (Path != NULL) { + for (i = StrLen(Path); i > 0; i--) { + if (Path[i-1] == '\\' || Path[i-1] == '/') { + FileName = Path + i; + break; + } + } + } + + return FileName; +} + +VOID ReplaceExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension) +{ + UINTN i; + + for (i = StrLen(Path); i >= 0; i--) { + if (Path[i] == '.') { + Path[i] = 0; + break; + } + if (Path[i] == '\\' || Path[i] == '/') + break; + } + StrCat(Path, Extension); +} + +// +// memory string search +// + +INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength) +{ + UINT8 *BufferPtr; + UINTN Offset; + + BufferPtr = Buffer; + BufferLength -= SearchStringLength; + for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) { + if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0) + return (INTN)Offset; + } + + return -1; +} + +// Performs a case-insensitive search of BigStr for SmallStr. +// Returns TRUE if found, FALSE if not. +BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) { + CHAR16 *SmallCopy, *BigCopy; + BOOLEAN Found = FALSE; + UINTN StartPoint = 0, NumCompares = 0, SmallLen = 0; + + if ((SmallStr != NULL) && (BigStr != NULL) && (StrLen(BigStr) >= StrLen(SmallStr))) { + SmallCopy = StrDuplicate(SmallStr); + BigCopy = StrDuplicate(BigStr); + StrLwr(SmallCopy); + StrLwr(BigCopy); + SmallLen = StrLen(SmallCopy); + NumCompares = StrLen(BigCopy) - SmallLen + 1; + while ((!Found) && (StartPoint < NumCompares)) { + Found = (StrnCmp(SmallCopy, &BigCopy[StartPoint++], SmallLen) == 0); + } // while + FreePool(SmallCopy); + FreePool(BigCopy); + } // if + + return (Found); +} // BOOLEAN StriSubCmp() + +// Merges two strings, creating a new one and returning a pointer to it. +// If AddChar != 0, the specified character is placed between the two original +// strings (unless the first string is NULL). The original input string +// *First is de-allocated and replaced by the new merged string. +// This is similar to StrCat, but safer and more flexible because +// MergeStrings allocates memory that's the correct size for the +// new merged string, so it can take a NULL *First and it cleans +// up the old memory. It should *NOT* be used with a constant +// *First, though.... +VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) { + UINTN Length1 = 0, Length2 = 0; + CHAR16* NewString; + + if (*First != NULL) + Length1 = StrLen(*First); + if (Second != NULL) + Length2 = StrLen(Second); + NewString = AllocatePool(sizeof(CHAR16) * (Length1 + Length2 + 2)); + NewString[0] = 0; + if (NewString != NULL) { + if (*First != NULL) { + StrCat(NewString, *First); + if (AddChar) { + NewString[Length1] = AddChar; + NewString[Length1 + 1] = 0; + } // if (AddChar) + } // if (First != NULL) + if (First != NULL) + StrCat(NewString, Second); + FreePool(*First); + *First = NewString; + } else { + Print(L"Error! Unable to allocate memory in MergeStrings()!\n"); + } // if/else +} // static CHAR16* MergeStrings() + +// Takes an input pathname (*Path) and locates the final directory component +// of that name. For instance, if the input path is 'EFI\foo\bar.efi', this +// function returns the string 'foo'. +// Assumes the pathname is separated with backslashes. +CHAR16 *FindLastDirName(IN CHAR16 *Path) { + UINTN i, StartOfElement = 0, EndOfElement = 0, PathLength, CopyLength; + CHAR16 *Found = NULL; + + PathLength = StrLen(Path); + // Find start & end of target element + for (i = 0; i < PathLength; i++) { + if (Path[i] == '\\') { + StartOfElement = EndOfElement; + EndOfElement = i; + } // if + } // for + // Extract the target element + if (EndOfElement > 0) { + while ((StartOfElement < PathLength) && (Path[StartOfElement] == '\\')) { + StartOfElement++; + } // while + EndOfElement--; + if (EndOfElement >= StartOfElement) { + CopyLength = EndOfElement - StartOfElement + 1; + Found = StrDuplicate(&Path[StartOfElement]); + if (Found != NULL) + Found[CopyLength] = 0; + } // if (EndOfElement >= StartOfElement) + } // if (EndOfElement > 0) + return (Found); +} // CHAR16 *FindLastDirName + +// Returns the directory portion of a pathname. For instance, +// if FullPath is 'EFI\foo\bar.efi', this function returns the +// string 'EFI\foo'. +CHAR16 *FindPath(IN CHAR16* FullPath) { + UINTN i, LastBackslash = 0; + CHAR16 *PathOnly; + + for (i = 0; i < StrLen(FullPath); i++) { + if (FullPath[i] == '\\') + LastBackslash = i; + } // for + PathOnly = StrDuplicate(FullPath); + PathOnly[LastBackslash] = 0; + return (PathOnly); +} + +// Returns all the digits in the input string, including intervening +// non-digit characters. For instance, if InString is "foo-3.3.4-7.img", +// this function returns "3.3.4-7". If InString contains no digits, +// the return value is NULL. +CHAR16 *FindNumbers(IN CHAR16 *InString) { + UINTN i, StartOfElement, EndOfElement = 0, InLength, CopyLength; + CHAR16 *Found = NULL; + + InLength = StartOfElement = StrLen(InString); + // Find start & end of target element + for (i = 0; i < InLength; i++) { + if ((InString[i] >= '0') && (InString[i] <= '9')) { + if (StartOfElement > i) + StartOfElement = i; + if (EndOfElement < i) + EndOfElement = i; + } // if + } // for + // Extract the target element + if (EndOfElement > 0) { + if (EndOfElement >= StartOfElement) { + CopyLength = EndOfElement - StartOfElement + 1; + Found = StrDuplicate(&InString[StartOfElement]); + if (Found != NULL) + Found[CopyLength] = 0; + } // if (EndOfElement >= StartOfElement) + } // if (EndOfElement > 0) + return (Found); +} // CHAR16 *FindNumbers() diff --git a/refind/lib.h b/refind/lib.h new file mode 100644 index 0000000..9d8263f --- /dev/null +++ b/refind/lib.h @@ -0,0 +1,104 @@ +/* + * refit/lib.h + * General header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __LIB_H_ +#define __LIB_H_ + +#include "efi.h" +#include "efilib.h" + +#include "libeg.h" + +// +// lib module +// + +// types + +typedef struct { + EFI_STATUS LastStatus; + EFI_FILE_HANDLE DirHandle; + BOOLEAN CloseDirHandle; + EFI_FILE_INFO *LastFileInfo; +} REFIT_DIR_ITER; + +#define DISK_KIND_INTERNAL (0) +#define DISK_KIND_EXTERNAL (1) +#define DISK_KIND_OPTICAL (2) + +#define IS_EXTENDED_PART_TYPE(type) ((type) == 0x05 || (type) == 0x0f || (type) == 0x85) + +EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle); +VOID UninitRefitLib(VOID); +EFI_STATUS ReinitRefitLib(VOID); + +VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount); +VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement); +VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount /*, IN Callback*/); + +VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList); + +VOID ScanVolumes(VOID); + +BOOLEAN FileExists(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath); + +EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode); + +VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter); +BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, OUT EFI_FILE_INFO **DirEntry); +EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter); + +CHAR16 * Basename(IN CHAR16 *Path); +VOID ReplaceExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension); + +INTN FindMem(IN VOID *Buffer, IN UINTN BufferLength, IN VOID *SearchString, IN UINTN SearchStringLength); +VOID ReinitVolumes(VOID); + +BOOLEAN StriSubCmp(IN CHAR16 *TargetStr, IN CHAR16 *BigStr); +VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar); +CHAR16 *FindLastDirName(IN CHAR16 *Path); +CHAR16 *FindPath(IN CHAR16* FullPath); +CHAR16 *FindNumbers(IN CHAR16 *InString); + +#endif \ No newline at end of file diff --git a/refind/main.c b/refind/main.c new file mode 100644 index 0000000..b1839c9 --- /dev/null +++ b/refind/main.c @@ -0,0 +1,1373 @@ +/* + * refind/main.c + * Main code for the boot menu + * + * Copyright (c) 2006-2010 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#include "global.h" +#include "config.h" +#include "screen.h" +#include "lib.h" +#include "icns.h" +#include "menu.h" +#include "refit_call_wrapper.h" +#include "../include/syslinux_mbr.h" + +// +// variables + +#define MACOSX_LOADER_PATH L"\\System\\Library\\CoreServices\\boot.efi" + +static REFIT_MENU_ENTRY MenuEntryAbout = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryReset = { L"Restart Computer", TAG_RESET, 1, 0, 'R', NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL }; +static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL }; + +static REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot" }; +static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL }; + +REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, FALSE, NULL, NULL, NULL, NULL }; + +// +// misc functions +// + +static VOID AboutrEFInd(VOID) +{ + if (AboutMenu.EntryCount == 0) { + AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.2"); + AddMenuInfoLine(&AboutMenu, L""); + AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); + AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); + AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others"); + AddMenuInfoLine(&AboutMenu, L""); + AddMenuInfoLine(&AboutMenu, L"Running on:"); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d", + ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1))); +#if defined(EFI32) + AddMenuInfoLine(&AboutMenu, L" Platform: x86 (32 bit)"); +#elif defined(EFIX64) + AddMenuInfoLine(&AboutMenu, L" Platform: x86_64 (64 bit)"); +#else + AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); +#endif + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", + ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & ((1 << 16) - 1))); + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription())); + AddMenuInfoLine(&AboutMenu, L""); + AddMenuInfoLine(&AboutMenu, L"For more information, see the rEFInd Web site:"); + AddMenuInfoLine(&AboutMenu, L"http://www.rodsbooks.com/refind/"); + AddMenuEntry(&AboutMenu, &MenuEntryReturn); + } + + RunMenu(&AboutMenu, NULL); +} /* VOID AboutrEFInd() */ + +static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, + IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, + IN CHAR16 *ImageTitle, + OUT UINTN *ErrorInStep) +{ + EFI_STATUS Status, ReturnStatus; + EFI_HANDLE ChildImageHandle; + EFI_LOADED_IMAGE *ChildLoadedImage; + UINTN DevicePathIndex; + CHAR16 ErrorInfo[256]; + CHAR16 *FullLoadOptions = NULL; + + Print(L"Starting %s\n", ImageTitle); + if (ErrorInStep != NULL) + *ErrorInStep = 0; + + // load the image into memory + ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty + for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) { + ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], NULL, 0, &ChildImageHandle); + if (ReturnStatus != EFI_NOT_FOUND) + break; + } + SPrint(ErrorInfo, 255, L"while loading %s", ImageTitle); + if (CheckError(Status, ErrorInfo)) { + if (ErrorInStep != NULL) + *ErrorInStep = 1; + goto bailout; + } + + // set load options + if (LoadOptions != NULL) { + ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage); + if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { + if (ErrorInStep != NULL) + *ErrorInStep = 2; + goto bailout_unload; + } + + if (LoadOptionsPrefix != NULL) { + FullLoadOptions = PoolPrint(L"%s %s ", LoadOptionsPrefix, LoadOptions); + // NOTE: That last space is also added by the EFI shell and seems to be significant + // when passing options to Apple's boot.efi... + LoadOptions = FullLoadOptions; + } + // NOTE: We also include the terminating null in the length for safety. + ChildLoadedImage->LoadOptions = (VOID *)LoadOptions; + ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(LoadOptions) + 1) * sizeof(CHAR16); + Print(L"Using load options '%s'\n", LoadOptions); + } + + // close open file handles + UninitRefitLib(); + + // turn control over to the image + // TODO: (optionally) re-enable the EFI watchdog timer! + ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); + // control returns here when the child image calls Exit() + SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle); + if (CheckError(Status, ErrorInfo)) { + if (ErrorInStep != NULL) + *ErrorInStep = 3; + } + + // re-open file handles + ReinitRefitLib(); + +bailout_unload: + // unload the image, we don't care if it works or not... + Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); +bailout: + if (FullLoadOptions != NULL) + FreePool(FullLoadOptions); + return ReturnStatus; +} /* static EFI_STATUS StartEFIImageList() */ + +static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, + IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, + IN CHAR16 *ImageTitle, + OUT UINTN *ErrorInStep) +{ + EFI_DEVICE_PATH *DevicePaths[2]; + + DevicePaths[0] = DevicePath; + DevicePaths[1] = NULL; + return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep); +} /* static EFI_STATUS StartEFIImage() */ + +// +// EFI OS loader functions +// + +static VOID StartLoader(IN LOADER_ENTRY *Entry) +{ + BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); + StartEFIImage(Entry->DevicePath, Entry->LoadOptions, + Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), NULL); + FinishExternalScreen(); +} + +// Locate an initrd or initramfs file that matches the kernel specified by LoaderPath. +// The matching file has a name that begins with "init" and includes the same version +// number string as is found in LoaderPath -- but not a longer version number string. +// For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels +// has a file called initramfs-3.3.0.img, this function will return the string +// '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file +// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match; +// however, initmine-3.3.0.img might match. (FindInitrd() returns the first match it +// finds). Thus, care should be taken to avoid placing duplicate matching files in +// the kernel's directory. +// If no matching init file can be found, returns NULL. +static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 *InitrdName = NULL, *FileName, *KernelVersion, *InitrdVersion, *Path; + REFIT_DIR_ITER DirIter; + EFI_FILE_INFO *DirEntry; + + FileName = Basename(LoaderPath); + KernelVersion = FindNumbers(FileName); + Path = FindPath(LoaderPath); + + DirIterOpen(Volume->RootDir, Path, &DirIter); + while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) { + InitrdVersion = FindNumbers(DirEntry->FileName); + if (KernelVersion != NULL) { +// if (StriSubCmp(KernelVersion, DirEntry->FileName)) { + if (StriCmp(InitrdVersion, KernelVersion) == 0) + InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName); +// } // if match found + } else { + if (InitrdVersion == NULL) + InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName); + } // if/else + if (InitrdVersion != NULL) + FreePool(InitrdVersion); + } // while + DirIterClose(&DirIter); + + // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed. + FreePool(KernelVersion); + FreePool(Path); + return (InitrdName); +} // static CHAR16 * FindInitrd() + +LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry) { + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + + return(Entry); +} // LOADER_ENTRY * AddPreparedLoaderEntry() + +// Creates a new LOADER_ENTRY data structure and populates it with +// default values from the specified Entry, or NULL values if Entry +// is unspecified (NULL). +// Returns a pointer to the new data structure, or NULL if it +// couldn't be allocated +LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry) { + LOADER_ENTRY *NewEntry = NULL; + + NewEntry = AllocateZeroPool(sizeof(LOADER_ENTRY)); + if (NewEntry != NULL) { + NewEntry->me.Title = NULL; + NewEntry->me.Tag = TAG_LOADER; + NewEntry->Enabled = TRUE; + NewEntry->UseGraphicsMode = FALSE; + NewEntry->OSType = 0; + if (Entry != NULL) { + NewEntry->LoaderPath = StrDuplicate(Entry->LoaderPath); + NewEntry->VolName = StrDuplicate(Entry->VolName); + NewEntry->DevicePath = Entry->DevicePath; + NewEntry->UseGraphicsMode = Entry->UseGraphicsMode; + NewEntry->LoadOptions = StrDuplicate(Entry->LoadOptions); + NewEntry->InitrdPath = StrDuplicate(Entry->InitrdPath); + } + } // if + return (NewEntry); +} // LOADER_ENTRY *InitializeLoaderEntry() + +// Prepare a REFIT_MENU_SCREEN data structure for a subscreen entry. This sets up +// the default entry that launches the boot loader using the same options as the +// main Entry does. Subsequent options can be added by the calling function. +// If a subscreen already exists in the Entry that's passed to this function, +// it's left unchanged and a pointer to it is returned. +// Returns a pointer to the new subscreen data structure, or NULL if there +// were problems allocating memory. +REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { + CHAR16 *FileName, *Temp; + REFIT_MENU_SCREEN *SubScreen = NULL; + LOADER_ENTRY *SubEntry; + + FileName = Basename(Entry->LoaderPath); + if (Entry->me.SubScreen == NULL) { // No subscreen yet; initialize default entry.... + SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + if (SubScreen != NULL) { + SubScreen->Title = PoolPrint(L"Boot Options for %s on %s", (Entry->Title != NULL) ? Entry->Title : FileName, Entry->VolName); + SubScreen->TitleImage = Entry->me.Image; + // default entry + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot using default options"; +// SubEntry->me.Title = (Entry->OSType == 'M') ? L"Boot Mac OS X" : PoolPrint(L"Run %s", FileName); + if ((SubEntry->InitrdPath != NULL) && (StrLen(SubEntry->InitrdPath) > 0) && (!StriSubCmp(L"initrd", SubEntry->LoadOptions))) { + Temp = PoolPrint(L"initrd=%s", SubEntry->InitrdPath); + MergeStrings(&SubEntry->LoadOptions, Temp, L' '); + FreePool(Temp); + } // if + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if (SubEntry != NULL) + } // if (SubScreen != NULL) + } else { // existing subscreen; less initialization, and just add new entry later.... + SubScreen = Entry->me.SubScreen; + } // if/else + return SubScreen; +} // REFIT_MENU_SCREEN *InitializeSubScreen() + +VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { + REFIT_MENU_SCREEN *SubScreen; + LOADER_ENTRY *SubEntry; + CHAR16 *FileName, *InitrdOption = NULL, *Temp; + CHAR16 DiagsFileName[256]; + REFIT_FILE *File; + UINTN TokenCount; + CHAR16 **TokenList; + + FileName = Basename(Entry->LoaderPath); + // create the submenu + if (StrLen(Entry->Title) == 0) { + FreePool(Entry->Title); + Entry->Title = NULL; + } + SubScreen = InitializeSubScreen(Entry); + + // loader-specific submenu entries + if (Entry->OSType == 'M') { // entries for Mac OS X +#if defined(EFIX64) + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X with a 64-bit kernel"; + SubEntry->LoadOptions = L"arch=x86_64"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X with a 32-bit kernel"; + SubEntry->LoadOptions = L"arch=i386"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if +#endif + + if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SINGLEUSER)) { + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in verbose mode"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + +#if defined(EFIX64) + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in verbose mode (64-bit)"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v arch=x86_64"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in verbose mode (32-bit)"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v arch=i386"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } +#endif + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Mac OS X in single user mode"; + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v -s"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + } // not single-user + + // check for Apple hardware diagnostics + StrCpy(DiagsFileName, L"\\System\\Library\\CoreServices\\.diagnostics\\diags.efi"); + if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.DisableFlags & DISABLE_FLAG_HWTEST)) { + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Run Apple Hardware Test"; + FreePool(SubEntry->LoaderPath); + SubEntry->LoaderPath = StrDuplicate(DiagsFileName); + SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + SubEntry->UseGraphicsMode = TRUE; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // if + } // if diagnostics entry found + + } else if (Entry->OSType == 'L') { // entries for Linux kernels with EFI stub loaders + File = ReadLinuxOptionsFile(Entry->LoaderPath, Volume); + if (File != NULL) { + if ((Temp = FindInitrd(Entry->LoaderPath, Volume)) != NULL) + InitrdOption = PoolPrint(L"initrd=%s", Temp); + TokenCount = ReadTokenLine(File, &TokenList); // read and discard first entry, since it's + FreeTokenLine(&TokenList, &TokenCount); // set up by InitializeSubScreen(), earlier.... + while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { + SubEntry = InitializeLoaderEntry(Entry); + SubEntry->me.Title = StrDuplicate(TokenList[0]); + if (SubEntry->LoadOptions != NULL) + FreePool(SubEntry->LoadOptions); + SubEntry->LoadOptions = StrDuplicate(TokenList[1]); + MergeStrings(&SubEntry->LoadOptions, InitrdOption, L' '); + FreeTokenLine(&TokenList, &TokenCount); + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // while + if (InitrdOption) + FreePool(InitrdOption); + if (Temp) + FreePool(Temp); + FreePool(File); + } // if Linux options file exists + + } else if (Entry->OSType == 'E') { // entries for ELILO + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = PoolPrint(L"Run %s in interactive mode", FileName); + SubEntry->LoadOptions = L"-p"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Linux for a 17\" iMac or a 15\" MacBook Pro (*)"; + SubEntry->UseGraphicsMode = TRUE; + SubEntry->LoadOptions = L"-d 0 i17"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Linux for a 20\" iMac (*)"; + SubEntry->UseGraphicsMode = TRUE; + SubEntry->LoadOptions = L"-d 0 i20"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Linux for a Mac Mini (*)"; + SubEntry->UseGraphicsMode = TRUE; + SubEntry->LoadOptions = L"-d 0 mini"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries"); + AddMenuInfoLine(SubScreen, L"marked with (*) may not work."); + + } else if (Entry->OSType == 'X') { // entries for xom.efi + // by default, skip the built-in selection and boot from hard disk only + Entry->LoadOptions = L"-s -h"; + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Windows from Hard Disk"; + SubEntry->LoadOptions = L"-s -h"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = L"Boot Windows from CD-ROM"; + SubEntry->LoadOptions = L"-s -c"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + + SubEntry = InitializeLoaderEntry(Entry); + if (SubEntry != NULL) { + SubEntry->me.Title = PoolPrint(L"Run %s in text mode", FileName); + SubEntry->UseGraphicsMode = FALSE; + SubEntry->LoadOptions = L"-v"; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } + } // entries for xom.efi + AddMenuEntry(SubScreen, &MenuEntryReturn); + Entry->me.SubScreen = SubScreen; +} // VOID GenerateSubScreen() + +// Returns options for a Linux kernel. Reads them from an options file in the +// kernel's directory; and if present, adds an initrd= option for an initial +// RAM disk file with the same version number as the kernel file. +static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 *Options = NULL, *InitrdName, *InitrdOption = NULL; + + Options = GetFirstOptionsFromFile(LoaderPath, Volume); + InitrdName = FindInitrd(LoaderPath, Volume); + if (InitrdName != NULL) + InitrdOption = PoolPrint(L"initrd=%s", InitrdName); + MergeStrings(&Options, InitrdOption, ' '); + if (InitrdOption != NULL) + FreePool(InitrdOption); + if (InitrdName != NULL) + FreePool(InitrdName); + return (Options); +} // static CHAR16 * GetMainLinuxOptions() + +// Sets a few defaults for a loader entry -- mainly the icon, but also the OS type +// code and shortcut letter. For Linux EFI stub loaders, also sets kernel options +// that will (with luck) work fairly automatically. +VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { + CHAR16 IconFileName[256]; + CHAR16 *FileName, *OSIconName = NULL, *Temp; + CHAR16 ShortcutLetter = 0; + + FileName = Basename(LoaderPath); + + // locate a custom icon for the loader + StrCpy(IconFileName, LoaderPath); + ReplaceExtension(IconFileName, L".icns"); + if (FileExists(Volume->RootDir, IconFileName)) { + Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128); + } // if + + Temp = FindLastDirName(LoaderPath); + MergeStrings(&OSIconName, Temp, L','); + FreePool(Temp); + if (OSIconName != NULL) { + ShortcutLetter = OSIconName[0]; + } + + // detect specific loaders + if (StriSubCmp(L"bzImage", LoaderPath) || StriSubCmp(L"vmlinuz", LoaderPath)) { + MergeStrings(&OSIconName, L"linux", L','); + Entry->OSType = 'L'; + if (ShortcutLetter == 0) + ShortcutLetter = 'L'; + Entry->LoadOptions = GetMainLinuxOptions(LoaderPath, Volume); + } else if (StriSubCmp(L"refit", LoaderPath)) { + MergeStrings(&OSIconName, L"refit", L','); + Entry->OSType = 'R'; + ShortcutLetter = 'R'; + } else if (StriCmp(LoaderPath, MACOSX_LOADER_PATH) == 0) { + MergeStrings(&OSIconName, L"mac", L','); + Entry->UseGraphicsMode = TRUE; + Entry->OSType = 'M'; + ShortcutLetter = 'M'; + } else if (StriCmp(FileName, L"diags.efi") == 0) { + MergeStrings(&OSIconName, L"hwtest", L','); + } else if (StriCmp(FileName, L"e.efi") == 0 || StriCmp(FileName, L"elilo.efi") == 0) { + MergeStrings(&OSIconName, L"elilo,linux", L','); + Entry->OSType = 'E'; + if (ShortcutLetter == 0) + ShortcutLetter = 'L'; + } else if (StriCmp(FileName, L"cdboot.efi") == 0 || + StriCmp(FileName, L"bootmgr.efi") == 0 || + StriCmp(FileName, L"Bootmgfw.efi") == 0) { + MergeStrings(&OSIconName, L"win", L','); + Entry->OSType = 'W'; + ShortcutLetter = 'W'; + } else if (StriCmp(FileName, L"xom.efi") == 0) { + MergeStrings(&OSIconName, L"xom,win", L','); + Entry->UseGraphicsMode = TRUE; + Entry->OSType = 'X'; + ShortcutLetter = 'W'; + } + + if ((ShortcutLetter >= 'a') && (ShortcutLetter <= 'z')) + ShortcutLetter = ShortcutLetter - 'a' + 'A'; // convert lowercase to uppercase + Entry->me.ShortcutLetter = ShortcutLetter; + if (Entry->me.Image == NULL) + Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); +} // VOID SetLoaderDefaults() + +// Add a specified EFI boot loader to the list, using automatic settings +// for icons, options, etc. +LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) { + LOADER_ENTRY *Entry; + + Entry = InitializeLoaderEntry(NULL); + if (Entry != NULL) { + Entry->Title = StrDuplicate(LoaderTitle); + Entry->me.Title = PoolPrint(L"Boot %s from %s", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath + 1, Volume->VolName); + Entry->me.Row = 0; + Entry->me.BadgeImage = Volume->VolBadgeImage; + Entry->LoaderPath = StrDuplicate(LoaderPath); + Entry->VolName = Volume->VolName; + Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath); + SetLoaderDefaults(Entry, LoaderPath, Volume); + GenerateSubScreen(Entry, Volume); + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + } + + return(Entry); +} // LOADER_ENTRY * AddLoaderEntry() + +// Scan an individual directory for EFI boot loader files and, if found, +// add them to the list. +static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path) +{ + EFI_STATUS Status; + REFIT_DIR_ITER DirIter; + EFI_FILE_INFO *DirEntry; + CHAR16 FileName[256]; + + // Note: SelfDirPath includes a leading backslash ('\'), but Path + // doesn't, so we rejigger the string to compensate.... + if (!SelfDirPath || !Path || ((StriCmp(Path, &SelfDirPath[1]) == 0) && Volume != SelfVolume) || + (StriCmp(Path, &SelfDirPath[1]) != 0)) { + // look through contents of the directory + DirIterOpen(Volume->RootDir, Path, &DirIter); + while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) { + if (DirEntry->FileName[0] == '.' || + StriCmp(DirEntry->FileName, L"TextMode.efi") == 0 || + StriCmp(DirEntry->FileName, L"ebounce.efi") == 0 || + StriCmp(DirEntry->FileName, L"GraphicsConsole.efi") == 0) + continue; // skip this + + if (Path) + SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName); + else + SPrint(FileName, 255, L"\\%s", DirEntry->FileName); + AddLoaderEntry(FileName, NULL, Volume); + } + Status = DirIterClose(&DirIter); + if (Status != EFI_NOT_FOUND) { + if (Path) + SPrint(FileName, 255, L"while scanning the %s directory", Path); + else + StrCpy(FileName, L"while scanning the root directory"); + CheckError(Status, FileName); + } // if (Status != EFI_NOT_FOUND) + } // if not scanning our own directory +} /* static VOID ScanLoaderDir() */ + +static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { + EFI_STATUS Status; + REFIT_DIR_ITER EfiDirIter; + EFI_FILE_INFO *EfiDirEntry; + CHAR16 FileName[256]; +// LOADER_ENTRY *Entry; + + if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) { + // check for Mac OS X boot loader + StrCpy(FileName, MACOSX_LOADER_PATH); + if (FileExists(Volume->RootDir, FileName)) { + AddLoaderEntry(FileName, L"Mac OS X", Volume); + } + + // check for XOM + StrCpy(FileName, L"\\System\\Library\\CoreServices\\xom.efi"); + if (FileExists(Volume->RootDir, FileName)) { + AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume); + } + + // check for Microsoft boot loader/menu + StrCpy(FileName, L"\\EFI\\Microsoft\\Boot\\Bootmgfw.efi"); + if (FileExists(Volume->RootDir, FileName)) { + AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume); + } + + // scan the root directory for EFI executables + ScanLoaderDir(Volume, NULL); + // scan the elilo directory (as used on gimli's first Live CD) + ScanLoaderDir(Volume, L"elilo"); + // scan the boot directory + ScanLoaderDir(Volume, L"boot"); + + // scan subdirectories of the EFI directory (as per the standard) + DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter); + while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) { + if (StriCmp(EfiDirEntry->FileName, L"TOOLS") == 0 || EfiDirEntry->FileName[0] == '.') + continue; // skip this, doesn't contain boot loaders + SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName); + ScanLoaderDir(Volume, FileName); + } // while() + Status = DirIterClose(&EfiDirIter); + if (Status != EFI_NOT_FOUND) + CheckError(Status, L"while scanning the EFI directory"); + } // if +} // static VOID ScanEfiFiles() + +// Scan internal disks for valid EFI boot loaders.... +static VOID ScanInternal(VOID) { + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_INTERNAL) { + ScanEfiFiles(Volumes[VolumeIndex]); + } + } // for +} // static VOID ScanInternal() + +// Scan external disks for valid EFI boot loaders.... +static VOID ScanExternal(VOID) { + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_EXTERNAL) { + ScanEfiFiles(Volumes[VolumeIndex]); + } + } // for +} // static VOID ScanExternal() + +// Scan internal disks for valid EFI boot loaders.... +static VOID ScanOptical(VOID) { + UINTN VolumeIndex; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + if (Volumes[VolumeIndex]->DiskKind == DISK_KIND_OPTICAL) { + ScanEfiFiles(Volumes[VolumeIndex]); + } + } // for +} // static VOID ScanOptical() + +// +// legacy boot functions +// + +static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN PartitionIndex) +{ + EFI_STATUS Status; + UINT8 SectorBuffer[512]; + MBR_PARTITION_INFO *MbrTable, *EMbrTable; + UINT32 ExtBase, ExtCurrent, NextExtCurrent; + UINTN LogicalPartitionIndex = 4; + UINTN i; + BOOLEAN HaveBootCode; + + // read MBR + Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) + return EFI_NOT_FOUND; // safety measure #1 + + // add boot code if necessary + HaveBootCode = FALSE; + for (i = 0; i < MBR_BOOTCODE_SIZE; i++) { + if (SectorBuffer[i] != 0) { + HaveBootCode = TRUE; + break; + } + } + if (!HaveBootCode) { + // no boot code found in the MBR, add the syslinux MBR code + SetMem(SectorBuffer, MBR_BOOTCODE_SIZE, 0); + CopyMem(SectorBuffer, syslinux_mbr, SYSLINUX_MBR_SIZE); + } + + // set the partition active + MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + ExtBase = 0; + for (i = 0; i < 4; i++) { + if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80) + return EFI_NOT_FOUND; // safety measure #2 + if (i == PartitionIndex) + MbrTable[i].Flags = 0x80; + else if (PartitionIndex >= 4 && IS_EXTENDED_PART_TYPE(MbrTable[i].Type)) { + MbrTable[i].Flags = 0x80; + ExtBase = MbrTable[i].StartLBA; + } else + MbrTable[i].Flags = 0x00; + } + + // write MBR + Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + + if (PartitionIndex >= 4) { + // we have to activate a logical partition, so walk the EMBR chain + + // NOTE: ExtBase was set above while looking at the MBR table + for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { + // read current EMBR + Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) + return EFI_NOT_FOUND; // safety measure #3 + + // scan EMBR, set appropriate partition active + EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); + NextExtCurrent = 0; + for (i = 0; i < 4; i++) { + if (EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) + return EFI_NOT_FOUND; // safety measure #4 + if (EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0) + break; + if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) { + // link to next EMBR + NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; + EMbrTable[i].Flags = (PartitionIndex >= LogicalPartitionIndex) ? 0x80 : 0x00; + break; + } else { + // logical partition + EMbrTable[i].Flags = (PartitionIndex == LogicalPartitionIndex) ? 0x80 : 0x00; + LogicalPartitionIndex++; + } + } + + // write current EMBR + Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer); + if (EFI_ERROR(Status)) + return Status; + + if (PartitionIndex < LogicalPartitionIndex) + break; // stop the loop, no need to touch further EMBRs + } + + } + + return EFI_SUCCESS; +} /* static EFI_STATUS ActivateMbrPartition() */ + +// early 2006 Core Duo / Core Solo models +static UINT8 LegacyLoaderDevicePath1Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// mid-2006 Mac Pro (and probably other Core 2 models) +static UINT8 LegacyLoaderDevicePath2Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// mid-2007 MBP ("Santa Rosa" based models) +static UINT8 LegacyLoaderDevicePath3Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// early-2008 MBA +static UINT8 LegacyLoaderDevicePath4Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; +// late-2008 MB/MBP (NVidia chipset) +static UINT8 LegacyLoaderDevicePath5Data[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; + +static EFI_DEVICE_PATH *LegacyLoaderList[] = { + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath1Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath2Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath3Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath4Data, + (EFI_DEVICE_PATH *)LegacyLoaderDevicePath5Data, + NULL +}; + +#define MAX_DISCOVERED_PATHS (16) + +static VOID StartLegacy(IN LEGACY_ENTRY *Entry) +{ + EFI_STATUS Status; + EG_IMAGE *BootLogoImage; + UINTN ErrorInStep = 0; + EFI_DEVICE_PATH *DiscoveredPathList[MAX_DISCOVERED_PATHS]; + + BeginExternalScreen(TRUE, L"Booting Legacy OS"); + + BootLogoImage = LoadOSIcon(Entry->Volume->OSIconName, L"legacy", TRUE); + if (BootLogoImage != NULL) + BltImageAlpha(BootLogoImage, + (UGAWidth - BootLogoImage->Width ) >> 1, + (UGAHeight - BootLogoImage->Height) >> 1, + &StdBackgroundPixel); + + if (Entry->Volume->IsMbrPartition) + ActivateMbrPartition(Entry->Volume->WholeDiskBlockIO, Entry->Volume->MbrPartitionIndex); + + ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); + + Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &ErrorInStep); + if (Status == EFI_NOT_FOUND) { + if (ErrorInStep == 1) { + Print(L"\nPlease make sure that you have the latest firmware update installed.\n"); + } else if (ErrorInStep == 3) { + Print(L"\nThe firmware refused to boot from the selected volume. Note that external\n" + L"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n"); + } + } + FinishExternalScreen(); +} /* static VOID StartLegacy() */ + +static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) +{ + LEGACY_ENTRY *Entry, *SubEntry; + REFIT_MENU_SCREEN *SubScreen; + CHAR16 *VolDesc; + CHAR16 ShortcutLetter = 0; + + if (LoaderTitle == NULL) { + if (Volume->OSName != NULL) { + LoaderTitle = Volume->OSName; + if (LoaderTitle[0] == 'W' || LoaderTitle[0] == 'L') + ShortcutLetter = LoaderTitle[0]; + } else + LoaderTitle = L"Legacy OS"; + } + if (Volume->VolName != NULL) + VolDesc = Volume->VolName; + else + VolDesc = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : L"HD"; + + // prepare the menu entry + Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + Entry->me.Title = PoolPrint(L"Boot %s from %s", LoaderTitle, VolDesc); + Entry->me.Tag = TAG_LEGACY; + Entry->me.Row = 0; + Entry->me.ShortcutLetter = ShortcutLetter; + Entry->me.Image = LoadOSIcon(Volume->OSIconName, L"legacy", FALSE); + Entry->me.BadgeImage = Volume->VolBadgeImage; + Entry->Volume = Volume; + Entry->LoadOptions = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : + ((Volume->DiskKind == DISK_KIND_EXTERNAL) ? L"USB" : L"HD"); + Entry->Enabled = TRUE; + + // create the submenu + SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); + SubScreen->Title = PoolPrint(L"Boot Options for %s on %s", LoaderTitle, VolDesc); + SubScreen->TitleImage = Entry->me.Image; + + // default entry + SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY)); + SubEntry->me.Title = PoolPrint(L"Boot %s", LoaderTitle); + SubEntry->me.Tag = TAG_LEGACY; + SubEntry->Volume = Entry->Volume; + SubEntry->LoadOptions = Entry->LoadOptions; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + + AddMenuEntry(SubScreen, &MenuEntryReturn); + Entry->me.SubScreen = SubScreen; + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + return Entry; +} /* static LEGACY_ENTRY * AddLegacyEntry() */ + +static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) { + UINTN VolumeIndex2; + BOOLEAN ShowVolume, HideIfOthersFound; + + ShowVolume = FALSE; + HideIfOthersFound = FALSE; + if (Volume->IsAppleLegacy) { + ShowVolume = TRUE; + HideIfOthersFound = TRUE; + } else if (Volume->HasBootCode) { + ShowVolume = TRUE; + if (Volume->BlockIO == Volume->WholeDiskBlockIO && + Volume->BlockIOOffset == 0 && + Volume->OSName == NULL) + // this is a whole disk (MBR) entry; hide if we have entries for partitions + HideIfOthersFound = TRUE; + } + if (HideIfOthersFound) { + // check for other bootable entries on the same disk + for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { + if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode && + Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO) + ShowVolume = FALSE; + } + } + + if (ShowVolume) + AddLegacyEntry(NULL, Volume); +} // static VOID ScanLegacyVolume() + +// Scan attached optical discs for legacy (BIOS) boot code +// and add anything found to the list.... +static VOID ScanLegacyDisc(VOID) +{ + UINTN VolumeIndex; + REFIT_VOLUME *Volume; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_OPTICAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for +} /* static VOID ScanLegacyDisc() */ + +// Scan internal hard disks for legacy (BIOS) boot code +// and add anything found to the list.... +static VOID ScanLegacyInternal(VOID) +{ + UINTN VolumeIndex; + REFIT_VOLUME *Volume; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_INTERNAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for +} /* static VOID ScanLegacyInternal() */ + +// Scan external disks for legacy (BIOS) boot code +// and add anything found to the list.... +static VOID ScanLegacyExternal(VOID) +{ + UINTN VolumeIndex; + REFIT_VOLUME *Volume; + + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { + Volume = Volumes[VolumeIndex]; + if (Volume->DiskKind == DISK_KIND_EXTERNAL) + ScanLegacyVolume(Volume, VolumeIndex); + } // for +} /* static VOID ScanLegacyExternal() */ + +// +// pre-boot tool functions +// + +static VOID StartTool(IN LOADER_ENTRY *Entry) +{ + BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start " as assigned below + StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath), + Basename(Entry->LoaderPath), NULL); + FinishExternalScreen(); +} /* static VOID StartTool() */ + +static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN EG_IMAGE *Image, + IN CHAR16 ShortcutLetter, IN BOOLEAN UseGraphicsMode) +{ + LOADER_ENTRY *Entry; + + Entry = AllocateZeroPool(sizeof(LOADER_ENTRY)); + + Entry->me.Title = PoolPrint(L"Start %s", LoaderTitle); + Entry->me.Tag = TAG_TOOL; + Entry->me.Row = 1; + Entry->me.ShortcutLetter = ShortcutLetter; + Entry->me.Image = Image; + Entry->LoaderPath = StrDuplicate(LoaderPath); + Entry->DevicePath = FileDevicePath(SelfLoadedImage->DeviceHandle, Entry->LoaderPath); + Entry->UseGraphicsMode = UseGraphicsMode; + + AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); + return Entry; +} /* static LOADER_ENTRY * AddToolEntry() */ + +static VOID ScanTool(VOID) +{ + CHAR16 FileName[256]; + LOADER_ENTRY *Entry; + + if (GlobalConfig.DisableFlags & DISABLE_FLAG_TOOLS) + return; + + // look for the EFI shell + if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SHELL)) { + SPrint(FileName, 255, L"%s\\apps\\shell.efi", SelfDirPath); + if (FileExists(SelfRootDir, FileName)) { + AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE); + } else { + StrCpy(FileName, L"\\efi\\tools\\shell.efi"); + if (FileExists(SelfRootDir, FileName)) { + AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE); + } + } + } + + // look for the GPT/MBR sync tool + StrCpy(FileName, L"\\efi\\tools\\gptsync.efi"); + if (FileExists(SelfRootDir, FileName)) { + AddToolEntry(FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE); + } + + // look for rescue Linux + StrCpy(FileName, L"\\efi\\rescue\\elilo.efi"); + if (SelfVolume != NULL && FileExists(SelfRootDir, FileName)) { + Entry = AddToolEntry(FileName, L"Rescue Linux", BuiltinIcon(BUILTIN_ICON_TOOL_RESCUE), '0', FALSE); + + if (UGAWidth == 1440 && UGAHeight == 900) + Entry->LoadOptions = L"-d 0 i17"; + else if (UGAWidth == 1680 && UGAHeight == 1050) + Entry->LoadOptions = L"-d 0 i20"; + else + Entry->LoadOptions = L"-d 0 mini"; + } +} + + +#ifdef DEBIAN_ENABLE_EFI110 +// +// pre-boot driver functions +// + +static VOID ScanDriverDir(IN CHAR16 *Path) +{ + EFI_STATUS Status; + REFIT_DIR_ITER DirIter; + EFI_FILE_INFO *DirEntry; + CHAR16 FileName[256]; + + // look through contents of the directory + DirIterOpen(SelfRootDir, Path, &DirIter); + while (DirIterNext(&DirIter, 2, L"*.EFI", &DirEntry)) { + if (DirEntry->FileName[0] == '.') + continue; // skip this + + SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName); + Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName), + L"", DirEntry->FileName, DirEntry->FileName, NULL); + } + Status = DirIterClose(&DirIter); + if (Status != EFI_NOT_FOUND) { + SPrint(FileName, 255, L"while scanning the %s directory", Path); + CheckError(Status, FileName); + } +} + +static EFI_STATUS ConnectAllDriversToAllControllers(VOID) +{ + EFI_STATUS Status; + UINTN AllHandleCount; + EFI_HANDLE *AllHandleBuffer; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINT32 *HandleType; + UINTN HandleIndex; + BOOLEAN Parent; + BOOLEAN Device; + + Status = LibLocateHandle(AllHandles, + NULL, + NULL, + &AllHandleCount, + &AllHandleBuffer); + if (EFI_ERROR(Status)) + return Status; + + for (Index = 0; Index < AllHandleCount; Index++) { + // + // Scan the handle database + // + Status = LibScanHandleDatabase(NULL, + NULL, + AllHandleBuffer[Index], + NULL, + &HandleCount, + &HandleBuffer, + &HandleType); + if (EFI_ERROR (Status)) + goto Done; + + Device = TRUE; + if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE) + Device = FALSE; + if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE) + Device = FALSE; + + if (Device) { + Parent = FALSE; + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE) + Parent = TRUE; + } + + if (!Parent) { + if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) { + Status = refit_call4_wrapper(BS->ConnectController, + AllHandleBuffer[Index], + NULL, + NULL, + TRUE); + } + } + } + + FreePool (HandleBuffer); + FreePool (HandleType); + } + +Done: + FreePool (AllHandleBuffer); + return Status; +} + +static VOID LoadDrivers(VOID) +{ + CHAR16 DirName[256]; + + // load drivers from /efi/refind/drivers + SPrint(DirName, 255, L"%s\\drivers", SelfDirPath); + ScanDriverDir(DirName); + + // load drivers from /efi/tools/drivers + ScanDriverDir(L"\\efi\\tools\\drivers"); + + // connect all devices + ConnectAllDriversToAllControllers(); +} +#endif /* DEBIAN_ENABLE_EFI110 */ + +static VOID ScanForBootloaders(VOID) { + UINTN i; + + ScanVolumes(); + // Commented-out below: Was part of an attempt to get rEFInd to + // re-scan disk devices on pressing Esc; but doesn't work (yet), so + // removed.... +// MainMenu.Title = StrDuplicate(L"Main Menu 2"); +// MainMenu.TitleImage = NULL; +// MainMenu.InfoLineCount = 0; +// MainMenu.InfoLines = NULL; +// MainMenu.EntryCount = 0; +// MainMenu.Entries = NULL; +// MainMenu.TimeoutSeconds = 20; +// MainMenu.TimeoutText = StrDuplicate(L"Automatic boot"); + // DebugPause(); + + // scan for loaders and tools, add them to the menu + for (i = 0; i < NUM_SCAN_OPTIONS; i++) { + switch(GlobalConfig.ScanFor[i]) { + case 'c': case 'C': + ScanLegacyDisc(); + break; + case 'h': case 'H': + ScanLegacyInternal(); + break; + case 'b': case 'B': + ScanLegacyExternal(); + break; + case 'm': case 'M': + ScanUserConfigured(); + break; + case 'e': case 'E': + ScanExternal(); + break; + case 'i': case 'I': + ScanInternal(); + break; + case 'o': case 'O': + ScanOptical(); + break; + } // switch() + } // for + ScanTool(); + + // fixed other menu entries + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS)) { + MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); + AddMenuEntry(&MainMenu, &MenuEntryAbout); + } + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS) || MainMenu.EntryCount == 0) { + MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN); + AddMenuEntry(&MainMenu, &MenuEntryShutdown); + MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET); + AddMenuEntry(&MainMenu, &MenuEntryReset); + } + + // assign shortcut keys + for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++) + MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i); + + // wait for user ACK when there were errors + FinishTextScreen(FALSE); +} // static VOID ScanForBootloaders() + +// +// main entry point +// + +EFI_STATUS +EFIAPI +efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + BOOLEAN MainLoopRunning = TRUE; + REFIT_MENU_ENTRY *ChosenEntry; + UINTN MenuExit; + + // bootstrap + InitializeLib(ImageHandle, SystemTable); + InitScreen(); + Status = InitRefitLib(ImageHandle); + if (EFI_ERROR(Status)) + return Status; + + // read configuration + CopyMem(GlobalConfig.ScanFor, "ieo ", NUM_SCAN_OPTIONS); + ReadConfig(); + MainMenu.TimeoutSeconds = GlobalConfig.Timeout; + + // disable EFI watchdog timer + refit_call4_wrapper(BS->SetWatchdogTimer, 0x0000, 0x0000, 0x0000, NULL); + + // further bootstrap (now with config available) + SetupScreen(); +#ifdef DEBIAN_ENABLE_EFI110 + LoadDrivers(); +#endif /* DEBIAN_ENABLE_EFI110 */ + ScanForBootloaders(); + + while (MainLoopRunning) { + MenuExit = RunMainMenu(&MainMenu, GlobalConfig.DefaultSelection, &ChosenEntry); + + // We don't allow exiting the main menu with the Escape key. + if (MenuExit == MENU_EXIT_ESCAPE) { + // Commented-out below: Was part of an attempt to get rEFInd to + // re-scan disk devices on pressing Esc; but doesn't work (yet), so + // removed.... +// ReadConfig(); +// ScanForBootloaders(); +// SetupScreen(); + continue; + } + + switch (ChosenEntry->Tag) { + + case TAG_RESET: // Restart + TerminateScreen(); + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + MainLoopRunning = FALSE; // just in case we get this far + break; + + case TAG_SHUTDOWN: // Shut Down + TerminateScreen(); + refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL); + MainLoopRunning = FALSE; // just in case we get this far + break; + + case TAG_ABOUT: // About rEFInd + AboutrEFInd(); + break; + + case TAG_LOADER: // Boot OS via .EFI loader + StartLoader((LOADER_ENTRY *)ChosenEntry); + break; + + case TAG_LEGACY: // Boot legacy OS + StartLegacy((LEGACY_ENTRY *)ChosenEntry); + break; + + case TAG_TOOL: // Start a EFI tool + StartTool((LOADER_ENTRY *)ChosenEntry); + break; + + } + } + + // If we end up here, things have gone wrong. Try to reboot, and if that + // fails, go into an endless loop. + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + EndlessIdleLoop(); + + return EFI_SUCCESS; +} /* efi_main() */ diff --git a/refind/menu.c b/refind/menu.c new file mode 100644 index 0000000..aedeb22 --- /dev/null +++ b/refind/menu.c @@ -0,0 +1,852 @@ +/* + * refit/menu.c + * Menu functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#include "global.h" +#include "screen.h" +#include "lib.h" +#include "menu.h" +#include "config.h" +#include "libeg.h" +#include "refit_call_wrapper.h" + +#include "egemb_back_selected_small.h" +#include "egemb_arrow_left.h" +#include "egemb_arrow_right.h" + +// other menu definitions + +#define MENU_FUNCTION_INIT (0) +#define MENU_FUNCTION_CLEANUP (1) +#define MENU_FUNCTION_PAINT_ALL (2) +#define MENU_FUNCTION_PAINT_SELECTION (3) +#define MENU_FUNCTION_PAINT_TIMEOUT (4) + +typedef VOID (*MENU_STYLE_FUNC)(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); + +static CHAR16 ArrowUp[2] = { ARROW_UP, 0 }; +static CHAR16 ArrowDown[2] = { ARROW_DOWN, 0 }; + +#define TEXT_YMARGIN (2) +#define TEXT_XMARGIN (8) +#define TEXT_LINE_HEIGHT (FONT_CELL_HEIGHT + TEXT_YMARGIN * 2) +#define TITLEICON_SPACING (16) + +#define ROW0_TILESIZE (144) +#define ROW1_TILESIZE (64) +#define TILE_XSPACING (8) +#define TILE_YSPACING (16) + +// Alignment values for PaintIcon() +#define ALIGN_RIGHT 1 +#define ALIGN_LEFT 0 + +static EG_IMAGE *SelectionImages[4] = { NULL, NULL, NULL, NULL }; +static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 }; +static EG_IMAGE *TextBuffer = NULL; + +// Used in MainMenuStyle(), but must be persistent.... +UINTN row0PosX = 0, row0PosXRunning = 0, row1PosY = 0, row0Loaders = 0; + +// +// Graphics helper functions +// + +static VOID InitSelection(VOID) +{ + UINTN x, y, src_x, src_y; + EG_PIXEL *DestPtr, *SrcPtr; + + if (!AllowGraphicsMode) + return; + if (SelectionImages[0] != NULL) + return; + + // load small selection image + if (GlobalConfig.SelectionSmallFileName != NULL) { + SelectionImages[2] = egLoadImage(SelfDir, GlobalConfig.SelectionSmallFileName, FALSE); + } + if (SelectionImages[2] == NULL) + SelectionImages[2] = egPrepareEmbeddedImage(&egemb_back_selected_small, FALSE); + SelectionImages[2] = egEnsureImageSize(SelectionImages[2], + ROW1_TILESIZE, ROW1_TILESIZE, &MenuBackgroundPixel); + if (SelectionImages[2] == NULL) + return; + + // load big selection image + if (GlobalConfig.SelectionBigFileName != NULL) { + SelectionImages[0] = egLoadImage(SelfDir, GlobalConfig.SelectionBigFileName, FALSE); + SelectionImages[0] = egEnsureImageSize(SelectionImages[0], + ROW0_TILESIZE, ROW0_TILESIZE, &MenuBackgroundPixel); + } + if (SelectionImages[0] == NULL) { + // calculate big selection image from small one + + SelectionImages[0] = egCreateImage(ROW0_TILESIZE, ROW0_TILESIZE, FALSE); + if (SelectionImages[0] == NULL) { + egFreeImage(SelectionImages[2]); + SelectionImages[2] = NULL; + return; + } + + DestPtr = SelectionImages[0]->PixelData; + SrcPtr = SelectionImages[2]->PixelData; + for (y = 0; y < ROW0_TILESIZE; y++) { + if (y < (ROW1_TILESIZE >> 1)) + src_y = y; + else if (y < (ROW0_TILESIZE - (ROW1_TILESIZE >> 1))) + src_y = (ROW1_TILESIZE >> 1); + else + src_y = y - (ROW0_TILESIZE - ROW1_TILESIZE); + + for (x = 0; x < ROW0_TILESIZE; x++) { + if (x < (ROW1_TILESIZE >> 1)) + src_x = x; + else if (x < (ROW0_TILESIZE - (ROW1_TILESIZE >> 1))) + src_x = (ROW1_TILESIZE >> 1); + else + src_x = x - (ROW0_TILESIZE - ROW1_TILESIZE); + + *DestPtr++ = SrcPtr[src_y * ROW1_TILESIZE + src_x]; + } + } + } + + // non-selected background images + SelectionImages[1] = egCreateFilledImage(ROW0_TILESIZE, ROW0_TILESIZE, FALSE, &MenuBackgroundPixel); + SelectionImages[3] = egCreateFilledImage(ROW1_TILESIZE, ROW1_TILESIZE, FALSE, &MenuBackgroundPixel); +} + +// +// Scrolling functions +// + +static VOID InitScroll(OUT SCROLL_STATE *State, IN UINTN ItemCount, IN UINTN VisibleSpace) +{ + State->LastSelection = State->CurrentSelection = 0; + State->MaxIndex = (INTN)ItemCount - 1; + State->FirstVisible = 0; + if (VisibleSpace == 0) + State->MaxVisible = UGAWidth / (ROW0_TILESIZE + TILE_XSPACING) - 1; + else + State->MaxVisible = (INTN)VisibleSpace; + State->PaintAll = TRUE; + State->PaintSelection = FALSE; + + State->LastVisible = State->FirstVisible + State->MaxVisible - 1; +} + +static VOID UpdateScroll(IN OUT SCROLL_STATE *State, IN UINTN Movement) +{ + State->LastSelection = State->CurrentSelection; + + switch (Movement) { + case SCROLL_LINE_UP: + if (State->CurrentSelection > 0) { + State->CurrentSelection --; + } + break; + + case SCROLL_LINE_DOWN: + if (State->CurrentSelection < State->MaxIndex) { + State->CurrentSelection ++; + } + break; + + // TODO: Better handling of SCROLL_PAGE_UP & SCROLL_PAGE_DOWN + case SCROLL_PAGE_UP: + case SCROLL_FIRST: + if (State->CurrentSelection > 0) { + State->PaintAll = TRUE; + State->CurrentSelection = 0; + } + break; + + case SCROLL_PAGE_DOWN: + case SCROLL_LAST: + if (State->CurrentSelection < State->MaxIndex) { + State->PaintAll = TRUE; + State->CurrentSelection = State->MaxIndex; + } + break; + + case SCROLL_NONE: + break; + + } + + if (!State->PaintAll && State->CurrentSelection != State->LastSelection) + State->PaintSelection = TRUE; + State->LastVisible = State->FirstVisible + State->MaxVisible - 1; +} + +// +// menu helper functions +// + +VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine) +{ + AddListElement((VOID ***) &(Screen->InfoLines), &(Screen->InfoLineCount), InfoLine); +} + +VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry) +{ + AddListElement((VOID ***) &(Screen->Entries), &(Screen->EntryCount), Entry); +} + +VOID FreeMenu(IN REFIT_MENU_SCREEN *Screen) +{ + if (Screen->Entries) + FreePool(Screen->Entries); +} + +static INTN FindMenuShortcutEntry(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *Shortcut) +{ + UINTN i; + + if (Shortcut == NULL) + return (-1); + + if (StrLen(Shortcut) == 1) { + if (Shortcut[0] >= 'a' && Shortcut[0] <= 'z') + Shortcut[0] -= ('a' - 'A'); + if (Shortcut[0]) { + for (i = 0; i < Screen->EntryCount; i++) { + if (Screen->Entries[i]->ShortcutDigit == Shortcut[0] || + Screen->Entries[i]->ShortcutLetter == Shortcut[0]) { + return i; + } // if + } // for + } // if + } else if (StrLen(Shortcut) > 1) { + for (i = 0; i < Screen->EntryCount; i++) { + if (StriSubCmp(Shortcut, Screen->Entries[i]->Title)) + return i; + } // for + } + return -1; +} + +// +// generic menu function +// + +static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC StyleFunc, IN INTN DefaultEntryIndex, OUT REFIT_MENU_ENTRY **ChosenEntry) +{ + SCROLL_STATE State; + EFI_STATUS Status; + EFI_INPUT_KEY key; + UINTN index; + INTN ShortcutEntry; + BOOLEAN HaveTimeout = FALSE; + UINTN TimeoutCountdown = 0; + CHAR16 *TimeoutMessage; + CHAR16 KeyAsString[2]; + UINTN MenuExit; + + if (Screen->TimeoutSeconds > 0) { + HaveTimeout = TRUE; + TimeoutCountdown = Screen->TimeoutSeconds * 10; + } + MenuExit = 0; + + StyleFunc(Screen, &State, MENU_FUNCTION_INIT, NULL); + // override the starting selection with the default index, if any + if (DefaultEntryIndex >= 0 && DefaultEntryIndex <= State.MaxIndex) { + State.CurrentSelection = DefaultEntryIndex; + UpdateScroll(&State, SCROLL_NONE); + } + + while (!MenuExit) { + // update the screen + if (State.PaintAll) { + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_ALL, NULL); + State.PaintAll = FALSE; + } else if (State.PaintSelection) { + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_SELECTION, NULL); + State.PaintSelection = FALSE; + } + + if (HaveTimeout) { + TimeoutMessage = PoolPrint(L"%s in %d seconds", Screen->TimeoutText, (TimeoutCountdown + 5) / 10); + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, TimeoutMessage); + FreePool(TimeoutMessage); + } + + // read key press (and wait for it if applicable) + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (Status == EFI_NOT_READY) { + if (HaveTimeout && TimeoutCountdown == 0) { + // timeout expired + MenuExit = MENU_EXIT_TIMEOUT; + break; + } else if (HaveTimeout) { + refit_call1_wrapper(BS->Stall, 100000); + TimeoutCountdown--; + } else + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + continue; + } + if (HaveTimeout) { + // the user pressed a key, cancel the timeout + StyleFunc(Screen, &State, MENU_FUNCTION_PAINT_TIMEOUT, L""); + HaveTimeout = FALSE; + } + + // react to key press + switch (key.ScanCode) { + case SCAN_UP: + case SCAN_LEFT: + UpdateScroll(&State, SCROLL_LINE_UP); + break; + case SCAN_DOWN: + case SCAN_RIGHT: + UpdateScroll(&State, SCROLL_LINE_DOWN); + break; + case SCAN_HOME: + UpdateScroll(&State, SCROLL_FIRST); + break; + case SCAN_END: + UpdateScroll(&State, SCROLL_LAST); + break; + case SCAN_PAGE_UP: + UpdateScroll(&State, SCROLL_PAGE_UP); + break; + case SCAN_PAGE_DOWN: + UpdateScroll(&State, SCROLL_PAGE_DOWN); + break; + case SCAN_ESC: + MenuExit = MENU_EXIT_ESCAPE; + break; + case SCAN_INSERT: + case SCAN_F2: + MenuExit = MENU_EXIT_DETAILS; + break; + case SCAN_F10: + egScreenShot(); + break; + } + switch (key.UnicodeChar) { + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + case ' ': + MenuExit = MENU_EXIT_ENTER; + break; + case '+': + MenuExit = MENU_EXIT_DETAILS; + break; + default: + KeyAsString[0] = key.UnicodeChar; + KeyAsString[1] = 0; + ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString); + if (ShortcutEntry >= 0) { + State.CurrentSelection = ShortcutEntry; + MenuExit = MENU_EXIT_ENTER; + } + break; + } + } + + StyleFunc(Screen, &State, MENU_FUNCTION_CLEANUP, NULL); + + if (ChosenEntry) + *ChosenEntry = Screen->Entries[State.CurrentSelection]; + return MenuExit; +} /* static UINTN RunGenericMenu( */ + +// +// text-mode generic style +// + +static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) +{ + INTN i; + UINTN MenuWidth, ItemWidth, MenuHeight; + static UINTN MenuPosY; + static CHAR16 **DisplayStrings; + CHAR16 *TimeoutMessage; + + switch (Function) { + + case MENU_FUNCTION_INIT: + // vertical layout + MenuPosY = 4; + if (Screen->InfoLineCount > 0) + MenuPosY += Screen->InfoLineCount + 1; + MenuHeight = ConHeight - MenuPosY; + if (Screen->TimeoutSeconds > 0) + MenuHeight -= 2; + InitScroll(State, Screen->EntryCount, MenuHeight); + + // determine width of the menu + MenuWidth = 20; // minimum + for (i = 0; i <= State->MaxIndex; i++) { + ItemWidth = StrLen(Screen->Entries[i]->Title); + if (MenuWidth < ItemWidth) + MenuWidth = ItemWidth; + } + if (MenuWidth > ConWidth - 6) + MenuWidth = ConWidth - 6; + + // prepare strings for display + DisplayStrings = AllocatePool(sizeof(CHAR16 *) * Screen->EntryCount); + for (i = 0; i <= State->MaxIndex; i++) + DisplayStrings[i] = PoolPrint(L" %-.*s ", MenuWidth, Screen->Entries[i]->Title); + // TODO: shorten strings that are too long (PoolPrint doesn't do that...) + // TODO: use more elaborate techniques for shortening too long strings (ellipses in the middle) + // TODO: account for double-width characters + + // initial painting + BeginTextScreen(Screen->Title); + if (Screen->InfoLineCount > 0) { + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 4 + i); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, Screen->InfoLines[i]); + } + } + + break; + + case MENU_FUNCTION_CLEANUP: + // release temporary memory + for (i = 0; i <= State->MaxIndex; i++) + FreePool(DisplayStrings[i]); + FreePool(DisplayStrings); + break; + + case MENU_FUNCTION_PAINT_ALL: + // paint the whole screen (initially and after scrolling) + for (i = 0; i <= State->MaxIndex; i++) { + if (i >= State->FirstVisible && i <= State->LastVisible) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (i - State->FirstVisible)); + if (i == State->CurrentSelection) + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); + else + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[i]); + } + } + // scrolling indicators + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_SCROLLARROW); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY); + if (State->FirstVisible > 0) + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowUp); + else + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, MenuPosY + State->MaxVisible); + if (State->LastVisible < State->MaxIndex) + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, ArrowDown); + else + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, L" "); + break; + + case MENU_FUNCTION_PAINT_SELECTION: + // redraw selection cursor + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->LastSelection - State->FirstVisible)); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_BASIC); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->LastSelection]); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 2, MenuPosY + (State->CurrentSelection - State->FirstVisible)); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_CHOICE_CURRENT); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, DisplayStrings[State->CurrentSelection]); + break; + + case MENU_FUNCTION_PAINT_TIMEOUT: + if (ParamText[0] == 0) { + // clear message + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, ConHeight - 1); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, BlankLine + 1); + } else { + // paint or update message + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, ConHeight - 1); + TimeoutMessage = PoolPrint(L"%s ", ParamText); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, TimeoutMessage); + FreePool(TimeoutMessage); + } + break; + + } +} + +// +// graphical generic style +// + + +static VOID DrawMenuText(IN CHAR16 *Text, IN UINTN SelectedWidth, IN UINTN XPos, IN UINTN YPos) +{ +// Print(L"Entering DrawMenuText(); Text is '%s', SelectedWidth is %d, XPos is %d, YPos is %d\n", +// Text, SelectedWidth, XPos, YPos); + if (TextBuffer == NULL) + TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, FALSE); + + egFillImage(TextBuffer, &MenuBackgroundPixel); + if (SelectedWidth > 0) { + // draw selection bar background + egFillImageArea(TextBuffer, 0, 0, SelectedWidth, TextBuffer->Height, + &SelectionBackgroundPixel); + } + + // render the text + egRenderText(Text, TextBuffer, TEXT_XMARGIN, TEXT_YMARGIN); + BltImage(TextBuffer, XPos, YPos); +} + +// Displays sub-menus +static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) +{ + INTN i; + UINTN ItemWidth; + static UINTN MenuWidth, EntriesPosX, EntriesPosY, TimeoutPosY; + + switch (Function) { + + case MENU_FUNCTION_INIT: + InitScroll(State, Screen->EntryCount, 0); + + // determine width of the menu + MenuWidth = 20; // minimum + for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { + ItemWidth = StrLen(Screen->InfoLines[i]); + if (MenuWidth < ItemWidth) + MenuWidth = ItemWidth; + } + for (i = 0; i <= State->MaxIndex; i++) { + ItemWidth = StrLen(Screen->Entries[i]->Title); + if (MenuWidth < ItemWidth) + MenuWidth = ItemWidth; + } + MenuWidth = TEXT_XMARGIN * 2 + MenuWidth * FONT_CELL_WIDTH; + if (MenuWidth > LAYOUT_TEXT_WIDTH) + MenuWidth = LAYOUT_TEXT_WIDTH; + + if (Screen->TitleImage) + EntriesPosX = (UGAWidth + (Screen->TitleImage->Width + TITLEICON_SPACING) - MenuWidth) >> 1; + else + EntriesPosX = (UGAWidth - MenuWidth) >> 1; + EntriesPosY = ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_YOFFSET + TEXT_LINE_HEIGHT * 2; + TimeoutPosY = EntriesPosY + (Screen->EntryCount + 1) * TEXT_LINE_HEIGHT; + + // initial painting + SwitchToGraphicsAndClear(); + egMeasureText(Screen->Title, &ItemWidth, NULL); + DrawMenuText(Screen->Title, 0, ((UGAWidth - ItemWidth) >> 1) - TEXT_XMARGIN, EntriesPosY - TEXT_LINE_HEIGHT * 2); + if (Screen->TitleImage) + BltImageAlpha(Screen->TitleImage, + EntriesPosX - (Screen->TitleImage->Width + TITLEICON_SPACING), EntriesPosY, + &MenuBackgroundPixel); + if (Screen->InfoLineCount > 0) { + for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { + DrawMenuText(Screen->InfoLines[i], 0, EntriesPosX, EntriesPosY); + EntriesPosY += TEXT_LINE_HEIGHT; + } + EntriesPosY += TEXT_LINE_HEIGHT; // also add a blank line + } + + break; + + case MENU_FUNCTION_CLEANUP: + // nothing to do + break; + + case MENU_FUNCTION_PAINT_ALL: + for (i = 0; i <= State->MaxIndex; i++) { + DrawMenuText(Screen->Entries[i]->Title, (i == State->CurrentSelection) ? MenuWidth : 0, + EntriesPosX, EntriesPosY + i * TEXT_LINE_HEIGHT); + } + break; + + case MENU_FUNCTION_PAINT_SELECTION: + // redraw selection cursor + DrawMenuText(Screen->Entries[State->LastSelection]->Title, 0, + EntriesPosX, EntriesPosY + State->LastSelection * TEXT_LINE_HEIGHT); + DrawMenuText(Screen->Entries[State->CurrentSelection]->Title, MenuWidth, + EntriesPosX, EntriesPosY + State->CurrentSelection * TEXT_LINE_HEIGHT); + break; + + case MENU_FUNCTION_PAINT_TIMEOUT: + DrawMenuText(ParamText, 0, EntriesPosX, TimeoutPosY); + break; + + } +} + +// +// graphical main menu style +// + +static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN XPos, UINTN YPos) +{ + UINTN ImageNum; + + ImageNum = ((Entry->Row == 0) ? 0 : 2) + (selected ? 0 : 1); + if (SelectionImages != NULL) + BltImageCompositeBadge(SelectionImages[ImageNum], + Entry->Image, Entry->BadgeImage, XPos, YPos); +} + +static VOID DrawMainMenuText(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) +{ + UINTN TextWidth, TextPosX; + + if (TextBuffer == NULL) + TextBuffer = egCreateImage(LAYOUT_TEXT_WIDTH, TEXT_LINE_HEIGHT, FALSE); + + egFillImage(TextBuffer, &MenuBackgroundPixel); + + // render the text + egMeasureText(Text, &TextWidth, NULL); + if (TextWidth > TextBuffer->Width) + TextPosX = 0; + else + TextPosX = (TextBuffer->Width - TextWidth) / 2; + egRenderText(Text, TextBuffer, TextPosX, 0); +// egRenderText(Text, TextBuffer, (TextBuffer->Width - TextWidth) >> 1, 0); + BltImage(TextBuffer, XPos, YPos); +} + +static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, + UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { + INTN i; + + if (Screen->Entries[State->CurrentSelection]->Row == 0) { + if (State->CurrentSelection > State->LastVisible) { + State->LastVisible = State->CurrentSelection; + State->FirstVisible = 1 + State->CurrentSelection - State->MaxVisible; + if (State->FirstVisible < 0) // shouldn't happen, but just in case.... + State->FirstVisible = 0; + } // Scroll forward + if (State->CurrentSelection < State->FirstVisible) { + State->FirstVisible = State->CurrentSelection; + State->LastVisible = State->CurrentSelection + State->MaxVisible - 1; + } // Scroll backward + } + for (i = State->FirstVisible; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 0) { + if (i <= State->LastVisible) { + DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, + itemPosX[i - State->FirstVisible], row0PosY); + } // if + } else { + DrawMainMenuEntry(Screen->Entries[i], (i == State->CurrentSelection) ? TRUE : FALSE, + itemPosX[i], row1PosY); + } + } + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) + DrawMainMenuText(Screen->Entries[State->CurrentSelection]->Title, + (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY); +} // static VOID PaintAll() + +// Move the selection to State->CurrentSelection, adjusting icon row if necessary... +static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN *itemPosX, + UINTN row0PosY, UINTN row1PosY, UINTN textPosY) { + if ((State->CurrentSelection < State->LastVisible) && (State->CurrentSelection >= State->FirstVisible)) { + DrawMainMenuEntry(Screen->Entries[State->LastSelection], FALSE, + itemPosX[State->LastSelection - State->FirstVisible], + (Screen->Entries[State->LastSelection]->Row == 0) ? row0PosY : row1PosY); + DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE, + itemPosX[State->CurrentSelection - State->FirstVisible], + (Screen->Entries[State->CurrentSelection]->Row == 0) ? row0PosY : row1PosY); + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) + DrawMainMenuText(Screen->Entries[State->CurrentSelection]->Title, + (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY); + } else { + MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL); + } +} // static VOID MoveSelection(VOID) + +// Display an icon at the specified location. Uses the image specified by +// ExternalFilename if it's available, or BuiltInImage if it's not. The +// Y position is specified as the center value, and so is adjusted by half +// the icon's height. The X position is set along the icon's left +// edge if Alignment == ALIGN_LEFT, and along the right edge if +// Alignment == ALIGN_RIGHT +static VOID PaintIcon(IN EG_EMBEDDED_IMAGE *BuiltInIcon, IN CHAR16 *ExternalFilename, UINTN PosX, UINTN PosY, UINTN Alignment) { + EG_IMAGE *Icon = NULL; + + if (FileExists(SelfDir, ExternalFilename)) + Icon = egLoadIcon(SelfDir, ExternalFilename, 48); + if (Icon == NULL) + Icon = egPrepareEmbeddedImage(BuiltInIcon, TRUE); + if (Icon != NULL) { + if (Alignment == ALIGN_RIGHT) + PosX -= Icon->Width; + BltImageAlpha(Icon, PosX, PosY - (Icon->Height / 2), &MenuBackgroundPixel); + } +} // static VOID PaintArrow() + +// Display main menu in graphics mode +VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText) +{ + INTN i; + extern UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders; + UINTN row0Count, row1Count, row1PosX, row1PosXRunning; + static UINTN *itemPosX; + static UINTN row0PosY, textPosY; + + switch (Function) { + + case MENU_FUNCTION_INIT: + InitScroll(State, Screen->EntryCount, 0); + + // layout + row0Count = 0; + row1Count = 0; + row0Loaders = 0; + for (i = 0; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 1) { + row1Count++; + } else { + row0Loaders++; + if (row0Count < State->MaxVisible) + row0Count++; + } + } + row0PosX = (UGAWidth + TILE_XSPACING - (ROW0_TILESIZE + TILE_XSPACING) * row0Count) >> 1; + row0PosY = ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_YOFFSET; + row1PosX = (UGAWidth + TILE_XSPACING - (ROW1_TILESIZE + TILE_XSPACING) * row1Count) >> 1; + row1PosY = row0PosY + ROW0_TILESIZE + TILE_YSPACING; + if (row1Count > 0) + textPosY = row1PosY + ROW1_TILESIZE + TILE_YSPACING; + else + textPosY = row1PosY; + + itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount); + row0PosXRunning = row0PosX; + row1PosXRunning = row1PosX; + for (i = 0; i <= State->MaxIndex; i++) { + if (Screen->Entries[i]->Row == 0) { + itemPosX[i] = row0PosXRunning; + row0PosXRunning += ROW0_TILESIZE + TILE_XSPACING; + } else { + itemPosX[i] = row1PosXRunning; + row1PosXRunning += ROW1_TILESIZE + TILE_XSPACING; + } + } + // initial painting + InitSelection(); + SwitchToGraphicsAndClear(); + break; + + case MENU_FUNCTION_CLEANUP: + FreePool(itemPosX); + break; + + case MENU_FUNCTION_PAINT_ALL: + BltClearScreen(TRUE); + PaintAll(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); + // For PaintIcon() calls, the starting Y position is moved to the midpoint + // of the surrounding row; PaintIcon() adjusts this back up by half the + // icon's height to properly center it. + if (State->FirstVisible > 0) + PaintIcon(&egemb_arrow_left, L"icons\\arrow_left.icns", row0PosX - TILE_XSPACING, + row0PosY + (ROW0_TILESIZE / 2), ALIGN_RIGHT); + if (State->LastVisible < (row0Loaders - 1)) + PaintIcon(&egemb_arrow_right, L"icons\\arrow_right.icns", + (UGAWidth + (ROW0_TILESIZE + TILE_XSPACING) * State->MaxVisible) / 2 + TILE_XSPACING, + row0PosY + (ROW0_TILESIZE / 2), ALIGN_LEFT); + break; + + case MENU_FUNCTION_PAINT_SELECTION: + PaintSelection(Screen, State, itemPosX, row0PosY, row1PosY, textPosY); + break; + + case MENU_FUNCTION_PAINT_TIMEOUT: + if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) + DrawMainMenuText(ParamText, (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY + TEXT_LINE_HEIGHT); + break; + + } +} + +// +// user-callable dispatcher functions +// + +UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry) +{ + MENU_STYLE_FUNC Style = TextMenuStyle; + + if (AllowGraphicsMode) + Style = GraphicsMenuStyle; + + return RunGenericMenu(Screen, Style, -1, ChosenEntry); +} + +UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16* DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry) +{ + MENU_STYLE_FUNC Style = TextMenuStyle; + MENU_STYLE_FUNC MainStyle = TextMenuStyle; + REFIT_MENU_ENTRY *TempChosenEntry; + UINTN MenuExit = 0; + UINTN DefaultEntryIndex = -1; + + if (DefaultSelection != NULL) { + // Find a menu entry whose shortcut is the first character of DefaultSelection, or + // whose + DefaultEntryIndex = FindMenuShortcutEntry(Screen, DefaultSelection); + // If that didn't work, should we scan more characters? For now, no. + } + + if (AllowGraphicsMode) { + Style = GraphicsMenuStyle; + MainStyle = MainMenuStyle; + } + + while (!MenuExit) { + MenuExit = RunGenericMenu(Screen, MainStyle, DefaultEntryIndex, &TempChosenEntry); + Screen->TimeoutSeconds = 0; + + if (MenuExit == MENU_EXIT_DETAILS && TempChosenEntry->SubScreen != NULL) { + MenuExit = RunGenericMenu(TempChosenEntry->SubScreen, Style, -1, &TempChosenEntry); + if (MenuExit == MENU_EXIT_ESCAPE || TempChosenEntry->Tag == TAG_RETURN) + MenuExit = 0; + } + } + + if (ChosenEntry) + *ChosenEntry = TempChosenEntry; + return MenuExit; +} /* UINTN RunMainMenu() */ diff --git a/refind/menu.h b/refind/menu.h new file mode 100644 index 0000000..b0cb514 --- /dev/null +++ b/refind/menu.h @@ -0,0 +1,91 @@ +/* + * refind/menu.h + * menu functions header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Modifications copyright (c) 2012 Roderick W. Smith + * + * Modifications distributed under the terms of the GNU General Public + * License (GPL) version 3 (GPLv3), a copy of which must be distributed + * with this source code or binaries made from it. + * + */ + +#ifndef __REFIND_MENU_H_ +#define __REFIND_MENU_H_ + +#include "efi.h" +#include "efilib.h" + +#include "libeg.h" + +// +// menu module +// + +#define MENU_EXIT_ENTER (1) +#define MENU_EXIT_ESCAPE (2) +#define MENU_EXIT_DETAILS (3) +#define MENU_EXIT_TIMEOUT (4) + +#define TAG_RETURN (99) + +// scrolling definitions + +typedef struct { + INTN CurrentSelection, LastSelection, MaxIndex; + INTN FirstVisible, LastVisible, MaxVisible; + BOOLEAN PaintAll, PaintSelection; +} SCROLL_STATE; + +#define SCROLL_LINE_UP (0) +#define SCROLL_LINE_DOWN (1) +#define SCROLL_PAGE_UP (2) +#define SCROLL_PAGE_DOWN (3) +#define SCROLL_FIRST (4) +#define SCROLL_LAST (5) +#define SCROLL_NONE (6) + +struct _refit_menu_screen; + +VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine); +VOID AddMenuEntry(IN REFIT_MENU_SCREEN *Screen, IN REFIT_MENU_ENTRY *Entry); +VOID FreeMenu(IN REFIT_MENU_SCREEN *Screen); +VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText); +UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry); +UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16* DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry); + +#endif + +/* EOF */ diff --git a/refind/screen.c b/refind/screen.c new file mode 100644 index 0000000..fe57a23 --- /dev/null +++ b/refind/screen.c @@ -0,0 +1,452 @@ +/* + * refit/screen.c + * Screen handling functions + * + * Copyright (c) 2006 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "global.h" +#include "screen.h" +#include "config.h" +#include "refit_call_wrapper.h" + +#include "egemb_refind_banner.h" + +// Console defines and variables + +UINTN ConWidth; +UINTN ConHeight; +CHAR16 *BlankLine; + +static VOID SwitchToText(IN BOOLEAN CursorEnabled); +static VOID SwitchToGraphics(VOID); +static VOID DrawScreenHeader(IN CHAR16 *Title); + +// UGA defines and variables + +UINTN UGAWidth; +UINTN UGAHeight; +BOOLEAN AllowGraphicsMode; + +EG_PIXEL StdBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; +EG_PIXEL MenuBackgroundPixel = { 0xbf, 0xbf, 0xbf, 0 }; + +static BOOLEAN GraphicsScreenDirty; + +// general defines and variables + +static BOOLEAN haveError = FALSE; + +// +// Screen initialization and switching +// + +VOID InitScreen(VOID) +{ + UINTN i; + + // initialize libeg + egInitScreen(); + + if (egHasGraphicsMode()) { + egGetScreenSize(&UGAWidth, &UGAHeight); + AllowGraphicsMode = TRUE; + } else { + AllowGraphicsMode = FALSE; + egSetGraphicsModeEnabled(FALSE); // just to be sure we are in text mode + } + GraphicsScreenDirty = TRUE; + + // disable cursor + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); + + // get size of text console + if (refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, ST->ConOut->Mode->Mode, &ConWidth, &ConHeight) != EFI_SUCCESS) { + // use default values on error + ConWidth = 80; + ConHeight = 25; + } + + // make a buffer for a whole text line + BlankLine = AllocatePool((ConWidth + 1) * sizeof(CHAR16)); + for (i = 0; i < ConWidth; i++) + BlankLine[i] = ' '; + BlankLine[i] = 0; + + // show the banner (even when in graphics mode) + DrawScreenHeader(L"Initializing..."); +} + +VOID SetupScreen(VOID) +{ + if (GlobalConfig.TextOnly) { + // switch to text mode if requested + AllowGraphicsMode = FALSE; + SwitchToText(FALSE); + + } else if (AllowGraphicsMode) { + // clear screen and show banner + // (now we know we'll stay in graphics mode) + SwitchToGraphics(); + BltClearScreen(TRUE); + } +} + +static VOID SwitchToText(IN BOOLEAN CursorEnabled) +{ + egSetGraphicsModeEnabled(FALSE); + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, CursorEnabled); +} + +static VOID SwitchToGraphics(VOID) +{ + if (AllowGraphicsMode && !egIsGraphicsModeEnabled()) { + egSetGraphicsModeEnabled(TRUE); + GraphicsScreenDirty = TRUE; + } +} + +// +// Screen control for running tools +// + +VOID BeginTextScreen(IN CHAR16 *Title) +{ + DrawScreenHeader(Title); + SwitchToText(FALSE); + + // reset error flag + haveError = FALSE; +} + +VOID FinishTextScreen(IN BOOLEAN WaitAlways) +{ + if (haveError || WaitAlways) { + SwitchToText(FALSE); + PauseForKey(); + } + + // reset error flag + haveError = FALSE; +} + +VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title) +{ + if (!AllowGraphicsMode) + UseGraphicsMode = FALSE; + + if (UseGraphicsMode) { + SwitchToGraphics(); + BltClearScreen(FALSE); + } + + // show the header + DrawScreenHeader(Title); + + if (!UseGraphicsMode) + SwitchToText(TRUE); + + // reset error flag + haveError = FALSE; +} + +VOID FinishExternalScreen(VOID) +{ + // make sure we clean up later + GraphicsScreenDirty = TRUE; + + if (haveError) { + SwitchToText(FALSE); + PauseForKey(); + } + + // reset error flag + haveError = FALSE; +} + +VOID TerminateScreen(VOID) +{ + // clear text screen + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); + + // enable cursor + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); +} + +static VOID DrawScreenHeader(IN CHAR16 *Title) +{ + UINTN y; + + // clear to black background + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call1_wrapper(ST->ConOut->ClearScreen, ST->ConOut); + + // paint header background + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BANNER); + for (y = 0; y < 3; y++) { + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y); + Print(BlankLine); + } + + // print header text + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 3, 1); + Print(L"rEFInd - %s", Title); + + // reposition cursor + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, 4); +} + +// +// Keyboard input +// + +static BOOLEAN ReadAllKeyStrokes(VOID) +{ + BOOLEAN GotKeyStrokes; + EFI_STATUS Status; + EFI_INPUT_KEY key; + + GotKeyStrokes = FALSE; + for (;;) { + Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (Status == EFI_SUCCESS) { + GotKeyStrokes = TRUE; + continue; + } + break; + } + return GotKeyStrokes; +} + +VOID PauseForKey(VOID) +{ + UINTN index; + + Print(L"\n* Hit any key to continue *"); + + if (ReadAllKeyStrokes()) { // remove buffered key strokes + refit_call1_wrapper(BS->Stall, 5000000); // 5 seconds delay + ReadAllKeyStrokes(); // empty the buffer again + } + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + ReadAllKeyStrokes(); // empty the buffer to protect the menu + + Print(L"\n"); +} + +#if REFIT_DEBUG > 0 +VOID DebugPause(VOID) +{ + // show console and wait for key + SwitchToText(FALSE); + PauseForKey(); + + // reset error flag + haveError = FALSE; +} +#endif + +VOID EndlessIdleLoop(VOID) +{ + UINTN index; + + for (;;) { + ReadAllKeyStrokes(); + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + } +} + +// +// Error handling +// + +BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where) +{ + CHAR16 ErrorName[64]; + + if (!EFI_ERROR(Status)) + return FALSE; + + StatusToString(ErrorName, Status); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + Print(L"Fatal Error: %s %s\n", ErrorName, where); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + haveError = TRUE; + + //BS->Exit(ImageHandle, ExitStatus, ExitDataSize, ExitData); + + return TRUE; +} + +BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where) +{ + CHAR16 ErrorName[64]; + + if (!EFI_ERROR(Status)) + return FALSE; + + StatusToString(ErrorName, Status); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_ERROR); + Print(L"Error: %s %s\n", ErrorName, where); + refit_call2_wrapper(ST->ConOut->SetAttribute, ST->ConOut, ATTR_BASIC); + haveError = TRUE; + + return TRUE; +} + +// +// Graphics functions +// + +VOID SwitchToGraphicsAndClear(VOID) +{ + SwitchToGraphics(); + if (GraphicsScreenDirty) + BltClearScreen(TRUE); +} + +VOID BltClearScreen(IN BOOLEAN ShowBanner) +{ + static EG_IMAGE *Banner = NULL; + + if (ShowBanner && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_BANNER)) { + // load banner on first call + if (Banner == NULL) { + if (GlobalConfig.BannerFileName == NULL) + Banner = egPrepareEmbeddedImage(&egemb_refind_banner, FALSE); + else + Banner = egLoadImage(SelfDir, GlobalConfig.BannerFileName, FALSE); + if (Banner != NULL) + MenuBackgroundPixel = Banner->PixelData[0]; + } + + // clear and draw banner + egClearScreen(&MenuBackgroundPixel); + if (Banner != NULL) + BltImage(Banner, (UGAWidth - Banner->Width) >> 1, + ((UGAHeight - LAYOUT_TOTAL_HEIGHT) >> 1) + LAYOUT_BANNER_HEIGHT - Banner->Height); + + } else { + // clear to standard background color + egClearScreen(&StdBackgroundPixel); + } + + GraphicsScreenDirty = FALSE; +} + +VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos) +{ + egDrawImage(Image, XPos, YPos); + GraphicsScreenDirty = TRUE; +} + +VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel) +{ + EG_IMAGE *CompImage; + + // compose on background + CompImage = egCreateFilledImage(Image->Width, Image->Height, FALSE, BackgroundPixel); + egComposeImage(CompImage, Image, 0, 0); + + // blit to screen and clean up + egDrawImage(CompImage, XPos, YPos); + egFreeImage(CompImage); + GraphicsScreenDirty = TRUE; +} + +// VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos) +// { +// UINTN TotalWidth, TotalHeight, CompWidth, CompHeight, OffsetX, OffsetY; +// EG_IMAGE *CompImage; +// +// // initialize buffer with base image +// CompImage = egCopyImage(BaseImage); +// TotalWidth = BaseImage->Width; +// TotalHeight = BaseImage->Height; +// +// // place the top image +// CompWidth = TopImage->Width; +// if (CompWidth > TotalWidth) +// CompWidth = TotalWidth; +// OffsetX = (TotalWidth - CompWidth) >> 1; +// CompHeight = TopImage->Height; +// if (CompHeight > TotalHeight) +// CompHeight = TotalHeight; +// OffsetY = (TotalHeight - CompHeight) >> 1; +// egComposeImage(CompImage, TopImage, OffsetX, OffsetY); +// +// // blit to screen and clean up +// egDrawImage(CompImage, XPos, YPos); +// egFreeImage(CompImage); +// GraphicsScreenDirty = TRUE; +// } + +VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos) +{ + UINTN TotalWidth, TotalHeight, CompWidth = 0, CompHeight = 0, OffsetX = 0, OffsetY = 0; + EG_IMAGE *CompImage = NULL; + + // initialize buffer with base image + if (BaseImage != NULL) { + CompImage = egCopyImage(BaseImage); + TotalWidth = BaseImage->Width; + TotalHeight = BaseImage->Height; + } + + // place the top image + if ((TopImage != NULL) && (CompImage != NULL)) { + CompWidth = TopImage->Width; + if (CompWidth > TotalWidth) + CompWidth = TotalWidth; + OffsetX = (TotalWidth - CompWidth) >> 1; + CompHeight = TopImage->Height; + if (CompHeight > TotalHeight) + CompHeight = TotalHeight; + OffsetY = (TotalHeight - CompHeight) >> 1; + egComposeImage(CompImage, TopImage, OffsetX, OffsetY); + } + + // place the badge image + if (BadgeImage != NULL && CompImage != NULL && (BadgeImage->Width + 8) < CompWidth && (BadgeImage->Height + 8) < CompHeight) { + OffsetX += CompWidth - 8 - BadgeImage->Width; + OffsetY += CompHeight - 8 - BadgeImage->Height; + egComposeImage(CompImage, BadgeImage, OffsetX, OffsetY); + } + + // blit to screen and clean up + egDrawImage(CompImage, XPos, YPos); + egFreeImage(CompImage); + GraphicsScreenDirty = TRUE; +} diff --git a/refind/screen.h b/refind/screen.h new file mode 100644 index 0000000..1b2dfa6 --- /dev/null +++ b/refind/screen.h @@ -0,0 +1,101 @@ +/* + * refit/screen.h + * Screen management header file + * + * Copyright (c) 2006-2009 Christoph Pfisterer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SCREEN_H_ +#define __SCREEN_H_ + +#include "efi.h" +#include "efilib.h" + +#include "libeg.h" + +// +// screen module +// + +#define ATTR_BASIC (EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK) +#define ATTR_ERROR (EFI_YELLOW | EFI_BACKGROUND_BLACK) +#define ATTR_BANNER (EFI_WHITE | EFI_BACKGROUND_BLUE) +#define ATTR_CHOICE_BASIC ATTR_BASIC +#define ATTR_CHOICE_CURRENT (EFI_WHITE | EFI_BACKGROUND_GREEN) +#define ATTR_SCROLLARROW (EFI_LIGHTGREEN | EFI_BACKGROUND_BLACK) + +//#define LAYOUT_TEXT_WIDTH (512) +#define LAYOUT_TEXT_WIDTH (425) +#define LAYOUT_TOTAL_HEIGHT (368) +#define LAYOUT_BANNER_HEIGHT (32) +#define LAYOUT_BANNER_YOFFSET (LAYOUT_BANNER_HEIGHT + 32) + +#define FONT_CELL_WIDTH (7) +#define FONT_CELL_HEIGHT (12) + +extern UINTN ConWidth; +extern UINTN ConHeight; +extern CHAR16 *BlankLine; + +extern UINTN UGAWidth; +extern UINTN UGAHeight; +extern BOOLEAN AllowGraphicsMode; + +extern EG_PIXEL StdBackgroundPixel; +extern EG_PIXEL MenuBackgroundPixel; + +VOID InitScreen(VOID); +VOID SetupScreen(VOID); +VOID BeginTextScreen(IN CHAR16 *Title); +VOID FinishTextScreen(IN BOOLEAN WaitAlways); +VOID BeginExternalScreen(IN BOOLEAN UseGraphicsMode, IN CHAR16 *Title); +VOID FinishExternalScreen(VOID); +VOID TerminateScreen(VOID); +#if REFIT_DEBUG > 0 +VOID DebugPause(VOID); +#else +#define DebugPause() +#endif +VOID EndlessIdleLoop(VOID); +VOID PauseForKey(VOID); + +BOOLEAN CheckFatalError(IN EFI_STATUS Status, IN CHAR16 *where); +BOOLEAN CheckError(IN EFI_STATUS Status, IN CHAR16 *where); + +VOID SwitchToGraphicsAndClear(VOID); +VOID BltClearScreen(IN BOOLEAN ShowBanner); +VOID BltImage(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos); +VOID BltImageAlpha(IN EG_IMAGE *Image, IN UINTN XPos, IN UINTN YPos, IN EG_PIXEL *BackgroundPixel); +//VOID BltImageComposite(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN UINTN XPos, IN UINTN YPos); +VOID BltImageCompositeBadge(IN EG_IMAGE *BaseImage, IN EG_IMAGE *TopImage, IN EG_IMAGE *BadgeImage, IN UINTN XPos, IN UINTN YPos); + +#endif