mirror of
https://github.com/xcat2/xNBA.git
synced 2026-06-17 00:50:49 +00:00
Conflicts: src/config/general.h src/net/arp.c
This commit is contained in:
@@ -7,6 +7,7 @@ CLEANUP :=
|
||||
CFLAGS :=
|
||||
ASFLAGS :=
|
||||
LDFLAGS :=
|
||||
HOST_CFLAGS :=
|
||||
MAKEDEPS := Makefile
|
||||
|
||||
###############################################################################
|
||||
@@ -32,6 +33,7 @@ RANLIB := $(CROSS_COMPILE)ranlib
|
||||
OBJCOPY := $(CROSS_COMPILE)objcopy
|
||||
NM := $(CROSS_COMPILE)nm
|
||||
OBJDUMP := $(CROSS_COMPILE)objdump
|
||||
OPENSSL := openssl
|
||||
PARSEROM := ./util/parserom.pl
|
||||
FIXROM := ./util/fixrom.pl
|
||||
SYMCHECK := ./util/symcheck.pl
|
||||
|
||||
+146
-45
@@ -381,6 +381,7 @@ CFLAGS += -g
|
||||
ifeq ($(CCTYPE),gcc)
|
||||
CFLAGS += -ffreestanding
|
||||
CFLAGS += -Wall -W -Wformat-nonliteral
|
||||
HOST_CFLAGS += -Wall -W -Wformat-nonliteral
|
||||
endif
|
||||
ifeq ($(CCTYPE),icc)
|
||||
CFLAGS += -fno-builtin
|
||||
@@ -411,12 +412,14 @@ endif
|
||||
CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
|
||||
ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
|
||||
LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
|
||||
HOST_CFLAGS += -O2 -g
|
||||
|
||||
# Inhibit -Werror if NO_WERROR is specified on make command line
|
||||
#
|
||||
ifneq ($(NO_WERROR),1)
|
||||
CFLAGS += -Werror
|
||||
ASFLAGS += --fatal-warnings
|
||||
HOST_CFLAGS += -Werror
|
||||
endif
|
||||
|
||||
# Function trace recorder state in the last build. This is needed
|
||||
@@ -514,6 +517,136 @@ RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
|
||||
|
||||
DEBUG_TARGETS += dbg%.o c s
|
||||
|
||||
# List of embedded images included in the last build of embedded.o.
|
||||
# This is needed in order to correctly rebuild embedded.o whenever the
|
||||
# list of objects changes.
|
||||
#
|
||||
EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility
|
||||
EMBEDDED_LIST := $(BIN)/.embedded.list
|
||||
ifeq ($(wildcard $(EMBEDDED_LIST)),)
|
||||
EMBED_OLD := <invalid>
|
||||
else
|
||||
EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
|
||||
endif
|
||||
ifneq ($(EMBED_OLD),$(EMBED))
|
||||
$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
|
||||
endif
|
||||
|
||||
$(EMBEDDED_LIST) :
|
||||
|
||||
VERYCLEANUP += $(EMBEDDED_LIST)
|
||||
|
||||
EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED))
|
||||
EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
|
||||
EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
|
||||
\"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
|
||||
|
||||
embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST)
|
||||
|
||||
CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
|
||||
|
||||
# List of trusted root certificates
|
||||
#
|
||||
TRUSTED_LIST := $(BIN)/.trusted.list
|
||||
ifeq ($(wildcard $(TRUSTED_LIST)),)
|
||||
TRUST_OLD := <invalid>
|
||||
else
|
||||
TRUST_OLD := $(shell cat $(TRUSTED_LIST))
|
||||
endif
|
||||
ifneq ($(TRUST_OLD),$(TRUST))
|
||||
$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST))
|
||||
endif
|
||||
|
||||
$(TRUSTED_LIST) :
|
||||
|
||||
VERYCLEANUP += $(TRUSTED_LIST)
|
||||
|
||||
# Trusted root certificate fingerprints
|
||||
#
|
||||
TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST))
|
||||
TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\
|
||||
0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\
|
||||
$(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \
|
||||
-fingerprint))))$(COMMA))
|
||||
|
||||
rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
|
||||
|
||||
CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
|
||||
|
||||
# (Single-element) list of client certificates
|
||||
#
|
||||
CERT_LIST := $(BIN)/.certificate.list
|
||||
ifeq ($(wildcard $(CERT_LIST)),)
|
||||
CERT_OLD := <invalid>
|
||||
else
|
||||
CERT_OLD := $(shell cat $(CERT_LIST))
|
||||
endif
|
||||
ifneq ($(CERT_OLD),$(CERT))
|
||||
$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
|
||||
endif
|
||||
|
||||
$(CERT_LIST) :
|
||||
|
||||
VERYCLEANUP += $(CERT_LIST)
|
||||
|
||||
# Embedded client certificate
|
||||
#
|
||||
CERT_INC := $(BIN)/.certificate.der
|
||||
|
||||
ifdef CERT
|
||||
$(CERT_INC) : $(CERT) $(CERT_LIST)
|
||||
$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
|
||||
|
||||
clientcert_DEPS += $(CERT_INC)
|
||||
endif
|
||||
|
||||
CLEANUP += $(CERT_INC)
|
||||
|
||||
clientcert_DEPS += $(CERT_LIST)
|
||||
|
||||
CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
|
||||
|
||||
# (Single-element) list of client private keys
|
||||
#
|
||||
KEY_LIST := $(BIN)/.private_key.list
|
||||
ifeq ($(wildcard $(KEY_LIST)),)
|
||||
KEY_OLD := <invalid>
|
||||
else
|
||||
KEY_OLD := $(shell cat $(KEY_LIST))
|
||||
endif
|
||||
ifneq ($(KEY_OLD),$(KEY))
|
||||
$(shell $(ECHO) "$(KEY)" > $(KEY_LIST))
|
||||
endif
|
||||
|
||||
$(KEY_LIST) :
|
||||
|
||||
VERYCLEANUP += $(KEY_LIST)
|
||||
|
||||
# Embedded client private key
|
||||
#
|
||||
KEY_INC := $(BIN)/.private_key.der
|
||||
|
||||
ifdef KEY
|
||||
$(KEY_INC) : $(KEY) $(KEY_LIST)
|
||||
$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
|
||||
|
||||
clientcert_DEPS += $(KEY_INC)
|
||||
endif
|
||||
|
||||
CLEANUP += $(KEY_INC)
|
||||
|
||||
clientcert_DEPS += $(KEY_LIST)
|
||||
|
||||
CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"")
|
||||
|
||||
# These files use .incbin inline assembly to include a binary file.
|
||||
# Unfortunately ccache does not detect this dependency and caches
|
||||
# builds even when the binary file has changed.
|
||||
#
|
||||
$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
|
||||
|
||||
$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC)
|
||||
|
||||
# We automatically generate rules for any file mentioned in AUTO_SRCS
|
||||
# using the following set of templates. It would be cleaner to use
|
||||
# $(eval ...), but this function exists only in GNU make >= 3.80.
|
||||
@@ -529,7 +662,7 @@ define deps_template
|
||||
@$(MKDIR) -p $(BIN)/deps/$(dir $(1))
|
||||
@$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
|
||||
-Wno-error -M $(1) -MG -MP | \
|
||||
sed 's/\.o\s*:/_DEPS =/' > $(BIN)/deps/$(1).d
|
||||
sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
|
||||
endef
|
||||
|
||||
# rules_template : generate rules for a given source file
|
||||
@@ -603,40 +736,6 @@ drivers :
|
||||
roms :
|
||||
@$(ECHO) $(ROMS)
|
||||
|
||||
# List of embedded images included in the last build of embedded.o.
|
||||
# This is needed in order to correctly rebuild embedded.o whenever the
|
||||
# list of objects changes.
|
||||
#
|
||||
EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility
|
||||
EMBEDDED_LIST := $(BIN)/.embedded.list
|
||||
ifeq ($(wildcard $(EMBEDDED_LIST)),)
|
||||
EMBED_OLD := <invalid>
|
||||
else
|
||||
EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
|
||||
endif
|
||||
ifneq ($(EMBED_OLD),$(EMBED))
|
||||
$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
|
||||
endif
|
||||
|
||||
$(EMBEDDED_LIST) :
|
||||
|
||||
VERYCLEANUP += $(EMBEDDED_LIST)
|
||||
|
||||
EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED))
|
||||
EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
|
||||
EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
|
||||
\"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
|
||||
|
||||
$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
|
||||
|
||||
# This file uses .incbin inline assembly to include a binary file.
|
||||
# Unfortunately ccache does not detect this dependency and caches builds even
|
||||
# when the binary file has changed.
|
||||
#
|
||||
$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
|
||||
|
||||
CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
|
||||
|
||||
# Generate error usage information
|
||||
#
|
||||
$(BIN)/%.einfo : $(BIN)/%.o
|
||||
@@ -961,13 +1060,13 @@ endif # defined(BIN)
|
||||
#
|
||||
$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \
|
||||
-DBITSIZE=32 -DENDIAN=0 -o $@ $<
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \
|
||||
-DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
|
||||
CLEANUP += $(NRV2B)
|
||||
|
||||
$(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -O2 -o $@ $<
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $<
|
||||
CLEANUP += $(ZBIN)
|
||||
|
||||
###############################################################################
|
||||
@@ -975,23 +1074,25 @@ CLEANUP += $(ZBIN)
|
||||
# The EFI image converter
|
||||
#
|
||||
ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
|
||||
-I$(ZLIB_DIR)/include -idirafter include \
|
||||
-L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
|
||||
-I$(ZLIB_DIR)/include -idirafter include
|
||||
ELF2EFI_LDFLAGS := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
|
||||
-lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch
|
||||
|
||||
$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 -O2 -o $@
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \
|
||||
$(ELF2EFI_LDFLAGS) -o $@
|
||||
CLEANUP += $(ELF2EFI32)
|
||||
|
||||
$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 -O2 -o $@
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \
|
||||
$(ELF2EFI_LDFLAGS) -o $@
|
||||
CLEANUP += $(ELF2EFI64)
|
||||
|
||||
$(EFIROM) : util/efirom.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
|
||||
CLEANUP += $(EFIROM)
|
||||
|
||||
###############################################################################
|
||||
@@ -1000,7 +1101,7 @@ CLEANUP += $(EFIROM)
|
||||
#
|
||||
$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
|
||||
CLEANUP += $(ICCFIX)
|
||||
|
||||
###############################################################################
|
||||
@@ -1009,7 +1110,7 @@ CLEANUP += $(ICCFIX)
|
||||
#
|
||||
$(EINFO) : util/einfo.c $(MAKEDEPS)
|
||||
$(QM)$(ECHO) " [HOSTCC] $@"
|
||||
$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
|
||||
$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
|
||||
CLEANUP += $(EINFO)
|
||||
|
||||
###############################################################################
|
||||
|
||||
@@ -85,15 +85,9 @@ SRCDIRS += arch/i386/interface/pcbios
|
||||
SRCDIRS += arch/i386/interface/pxe
|
||||
SRCDIRS += arch/i386/interface/pxeparent
|
||||
SRCDIRS += arch/i386/interface/syslinux
|
||||
SRCDIRS += arch/i386/interface/vmware
|
||||
SRCDIRS += arch/i386/hci/commands
|
||||
|
||||
# The various xxx_loader.c files are #included into core/loader.c and
|
||||
# should not be compiled directly.
|
||||
#
|
||||
NON_AUTO_SRCS += arch/i386/core/aout_loader.c
|
||||
NON_AUTO_SRCS += arch/i386/core/freebsd_loader.c
|
||||
NON_AUTO_SRCS += arch/i386/core/wince_loader.c
|
||||
|
||||
# Include common x86 Makefile
|
||||
#
|
||||
MAKEDEPS += arch/x86/Makefile
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/* a.out */
|
||||
struct exec {
|
||||
unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */
|
||||
unsigned long a_text; /* text segment size */
|
||||
unsigned long a_data; /* initialized data size */
|
||||
unsigned long a_bss; /* uninitialized data size */
|
||||
unsigned long a_syms; /* symbol table size */
|
||||
unsigned long a_entry; /* entry point */
|
||||
unsigned long a_trsize; /* text relocation size */
|
||||
unsigned long a_drsize; /* data relocation size */
|
||||
};
|
||||
|
||||
struct aout_state {
|
||||
struct exec head;
|
||||
unsigned long curaddr;
|
||||
int segment; /* current segment number, -1 for none */
|
||||
unsigned long loc; /* start offset of current block */
|
||||
unsigned long skip; /* padding to be skipped to current segment */
|
||||
unsigned long toread; /* remaining data to be read in the segment */
|
||||
};
|
||||
|
||||
static struct aout_state astate;
|
||||
|
||||
static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
|
||||
static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
|
||||
{
|
||||
unsigned long start, mid, end, istart, iend;
|
||||
if (len < sizeof(astate.head)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&astate.head, data, sizeof(astate.head));
|
||||
if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("(a.out");
|
||||
aout_freebsd_probe();
|
||||
printf(")... ");
|
||||
/* Check the aout image */
|
||||
start = astate.head.a_entry;
|
||||
mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
|
||||
end = ((mid + 4095) & ~4095) + astate.head.a_bss;
|
||||
istart = 4096;
|
||||
iend = istart + (mid - start);
|
||||
if (!prep_segment(start, mid, end, istart, iend))
|
||||
return dead_download;
|
||||
astate.segment = -1;
|
||||
astate.loc = 0;
|
||||
astate.skip = 0;
|
||||
astate.toread = 0;
|
||||
return aout_download;
|
||||
}
|
||||
|
||||
static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
|
||||
{
|
||||
unsigned int offset; /* working offset in the current data block */
|
||||
|
||||
offset = 0;
|
||||
|
||||
#ifdef AOUT_LYNX_KDI
|
||||
astate.segment++;
|
||||
if (astate.segment == 0) {
|
||||
astate.curaddr = 0x100000;
|
||||
astate.head.a_entry = astate.curaddr + 0x20;
|
||||
}
|
||||
memcpy(phys_to_virt(astate.curaddr), data, len);
|
||||
astate.curaddr += len;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
do {
|
||||
if (astate.segment != -1) {
|
||||
if (astate.skip) {
|
||||
if (astate.skip >= len - offset) {
|
||||
astate.skip -= len - offset;
|
||||
break;
|
||||
}
|
||||
offset += astate.skip;
|
||||
astate.skip = 0;
|
||||
}
|
||||
|
||||
if (astate.toread) {
|
||||
if (astate.toread >= len - offset) {
|
||||
memcpy(phys_to_virt(astate.curaddr), data+offset,
|
||||
len - offset);
|
||||
astate.curaddr += len - offset;
|
||||
astate.toread -= len - offset;
|
||||
break;
|
||||
}
|
||||
memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
|
||||
offset += astate.toread;
|
||||
astate.toread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Data left, but current segment finished - look for the next
|
||||
* segment. This is quite simple for a.out files. */
|
||||
astate.segment++;
|
||||
switch (astate.segment) {
|
||||
case 0:
|
||||
/* read text */
|
||||
astate.curaddr = astate.head.a_entry;
|
||||
astate.skip = 4096;
|
||||
astate.toread = astate.head.a_text;
|
||||
break;
|
||||
case 1:
|
||||
/* read data */
|
||||
/* skip and curaddr may be wrong, but I couldn't find
|
||||
* examples where this failed. There is no reasonable
|
||||
* documentation for a.out available. */
|
||||
astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
|
||||
astate.curaddr = (astate.curaddr + 4095) & ~4095;
|
||||
astate.toread = astate.head.a_data;
|
||||
break;
|
||||
case 2:
|
||||
/* initialize bss and start kernel */
|
||||
astate.curaddr = (astate.curaddr + 4095) & ~4095;
|
||||
astate.skip = 0;
|
||||
astate.toread = 0;
|
||||
memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
|
||||
goto aout_startkernel;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (offset < len);
|
||||
|
||||
astate.loc += len;
|
||||
|
||||
if (eof) {
|
||||
unsigned long entry;
|
||||
|
||||
aout_startkernel:
|
||||
entry = astate.head.a_entry;
|
||||
done(1);
|
||||
|
||||
aout_freebsd_boot();
|
||||
#ifdef AOUT_LYNX_KDI
|
||||
xstart32(entry);
|
||||
#endif
|
||||
printf("unexpected a.out variant\n");
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
/* bootinfo */
|
||||
#define BOOTINFO_VERSION 1
|
||||
#define NODEV (-1) /* non-existent device */
|
||||
#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */
|
||||
#define PAGE_SIZE (1<<PAGE_SHIFT) /* bytes/page */
|
||||
#define PAGE_MASK (PAGE_SIZE-1)
|
||||
#define N_BIOS_GEOM 8
|
||||
|
||||
struct bootinfo {
|
||||
unsigned int bi_version;
|
||||
const unsigned char *bi_kernelname;
|
||||
struct nfs_diskless *bi_nfs_diskless;
|
||||
/* End of fields that are always present. */
|
||||
#define bi_endcommon bi_n_bios_used
|
||||
unsigned int bi_n_bios_used;
|
||||
unsigned long bi_bios_geom[N_BIOS_GEOM];
|
||||
unsigned int bi_size;
|
||||
unsigned char bi_memsizes_valid;
|
||||
unsigned char bi_pad[3];
|
||||
unsigned long bi_basemem;
|
||||
unsigned long bi_extmem;
|
||||
unsigned long bi_symtab;
|
||||
unsigned long bi_esymtab;
|
||||
/* Note that these are in the FreeBSD headers but were not here... */
|
||||
unsigned long bi_kernend; /* end of kernel space */
|
||||
unsigned long bi_envp; /* environment */
|
||||
unsigned long bi_modulep; /* preloaded modules */
|
||||
};
|
||||
|
||||
static struct bootinfo bsdinfo;
|
||||
|
||||
#ifdef ELF_IMAGE
|
||||
static Elf32_Shdr *shdr; /* To support the FreeBSD kludge! */
|
||||
static Address symtab_load;
|
||||
static Address symstr_load;
|
||||
static int symtabindex;
|
||||
static int symstrindex;
|
||||
#endif
|
||||
|
||||
static enum {
|
||||
Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
|
||||
} image_type = Unknown;
|
||||
|
||||
static unsigned int off;
|
||||
|
||||
|
||||
#ifdef ELF_IMAGE
|
||||
static void elf_freebsd_probe(void)
|
||||
{
|
||||
image_type = Elf;
|
||||
if ( (estate.e.elf32.e_entry & 0xf0000000) &&
|
||||
(estate.e.elf32.e_type == ET_EXEC))
|
||||
{
|
||||
image_type = Elf_FreeBSD;
|
||||
printf("/FreeBSD");
|
||||
off = -(estate.e.elf32.e_entry & 0xff000000);
|
||||
estate.e.elf32.e_entry += off;
|
||||
}
|
||||
/* Make sure we have a null to start with... */
|
||||
shdr = 0;
|
||||
|
||||
/* Clear the symbol index values... */
|
||||
symtabindex = -1;
|
||||
symstrindex = -1;
|
||||
|
||||
/* ...and the load addresses of the symbols */
|
||||
symtab_load = 0;
|
||||
symstr_load = 0;
|
||||
}
|
||||
|
||||
static void elf_freebsd_fixup_segment(void)
|
||||
{
|
||||
if (image_type == Elf_FreeBSD) {
|
||||
estate.p.phdr32[estate.segment].p_paddr += off;
|
||||
}
|
||||
}
|
||||
|
||||
static void elf_freebsd_find_segment_end(void)
|
||||
{
|
||||
/* Count the bytes read even for the last block
|
||||
* as we will need to know where the last block
|
||||
* ends in order to load the symbols correctly.
|
||||
* (plus it could be useful elsewhere...)
|
||||
* Note that we need to count the actual size,
|
||||
* not just the end of the disk image size.
|
||||
*/
|
||||
estate.curaddr +=
|
||||
(estate.p.phdr32[estate.segment].p_memsz -
|
||||
estate.p.phdr32[estate.segment].p_filesz);
|
||||
}
|
||||
|
||||
static int elf_freebsd_debug_loader(unsigned int offset)
|
||||
{
|
||||
/* No more segments to be loaded - time to start the
|
||||
* nasty state machine to support the loading of
|
||||
* FreeBSD debug symbols due to the fact that FreeBSD
|
||||
* uses/exports the kernel's debug symbols in order
|
||||
* to make much of the system work! Amazing (arg!)
|
||||
*
|
||||
* We depend on the fact that for the FreeBSD kernel,
|
||||
* there is only one section of debug symbols and that
|
||||
* the section is after all of the loaded sections in
|
||||
* the file. This assumes a lot but is somewhat required
|
||||
* to make this code not be too annoying. (Where do you
|
||||
* load symbols when the code has not loaded yet?)
|
||||
* Since this function is actually just a callback from
|
||||
* the network data transfer code, we need to be able to
|
||||
* work with the data as it comes in. There is no chance
|
||||
* for doing a seek other than forwards.
|
||||
*
|
||||
* The process we use is to first load the section
|
||||
* headers. Once they are loaded (shdr != 0) we then
|
||||
* look for where the symbol table and symbol table
|
||||
* strings are and setup some state that we found
|
||||
* them and fall into processing the first one (which
|
||||
* is the symbol table) and after that has been loaded,
|
||||
* we try the symbol strings. Note that the order is
|
||||
* actually required as the memory image depends on
|
||||
* the symbol strings being loaded starting at the
|
||||
* end of the symbol table. The kernel assumes this
|
||||
* layout of the image.
|
||||
*
|
||||
* At any point, if we get to the end of the load file
|
||||
* or the section requested is earlier in the file than
|
||||
* the current file pointer, we just end up falling
|
||||
* out of this and booting the kernel without this
|
||||
* information.
|
||||
*/
|
||||
|
||||
/* Make sure that the next address is long aligned... */
|
||||
/* Assumes size of long is a power of 2... */
|
||||
estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
|
||||
/* If we have not yet gotten the shdr loaded, try that */
|
||||
if (shdr == 0)
|
||||
{
|
||||
estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
|
||||
estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
|
||||
if (estate.toread)
|
||||
{
|
||||
#if ELF_DEBUG
|
||||
printf("shdr *, size %lX, curaddr %lX\n",
|
||||
estate.toread, estate.curaddr);
|
||||
#endif
|
||||
|
||||
/* Start reading at the curaddr and make that the shdr */
|
||||
shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
|
||||
|
||||
/* Start to read... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have the shdr loaded, check if we have found
|
||||
* the indexs where the symbols are supposed to be */
|
||||
if ((symtabindex == -1) && (symstrindex == -1))
|
||||
{
|
||||
int i;
|
||||
/* Make sure that the address is page aligned... */
|
||||
/* Symbols need to start in their own page(s)... */
|
||||
estate.curaddr = (estate.curaddr + 4095) & ~4095;
|
||||
|
||||
/* Need to make new indexes... */
|
||||
for (i=0; i < estate.e.elf32.e_shnum; i++)
|
||||
{
|
||||
if (shdr[i].sh_type == SHT_SYMTAB)
|
||||
{
|
||||
int j;
|
||||
for (j=0; j < estate.e.elf32.e_phnum; j++)
|
||||
{
|
||||
/* Check only for loaded sections */
|
||||
if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
|
||||
{
|
||||
/* Only the extra symbols */
|
||||
if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
|
||||
((shdr[i].sh_offset + shdr[i].sh_size) <=
|
||||
(estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
|
||||
{
|
||||
shdr[i].sh_offset=0;
|
||||
shdr[i].sh_size=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
|
||||
{
|
||||
symtabindex = i;
|
||||
symstrindex = shdr[i].sh_link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have a symbol table index and have not loaded it */
|
||||
if ((symtab_load == 0) && (symtabindex >= 0))
|
||||
{
|
||||
/* No symbol table yet? Load it first... */
|
||||
|
||||
/* This happens to work out in a strange way.
|
||||
* If we are past the point in the file already,
|
||||
* we will skip a *large* number of bytes which
|
||||
* ends up bringing us to the end of the file and
|
||||
* an old (default) boot. Less code and lets
|
||||
* the state machine work in a cleaner way but this
|
||||
* is a nasty side-effect trick... */
|
||||
estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
|
||||
|
||||
/* And we need to read this many bytes... */
|
||||
estate.toread = shdr[symtabindex].sh_size;
|
||||
|
||||
if (estate.toread)
|
||||
{
|
||||
#if ELF_DEBUG
|
||||
printf("db sym, size %lX, curaddr %lX\n",
|
||||
estate.toread, estate.curaddr);
|
||||
#endif
|
||||
/* Save where we are loading this... */
|
||||
symtab_load = estate.curaddr;
|
||||
|
||||
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
|
||||
estate.curaddr += sizeof(long);
|
||||
|
||||
/* Start to read... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((symstr_load == 0) && (symstrindex >= 0))
|
||||
{
|
||||
/* We have already loaded the symbol table, so
|
||||
* now on to the symbol strings... */
|
||||
|
||||
|
||||
/* Same nasty trick as above... */
|
||||
estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
|
||||
|
||||
/* And we need to read this many bytes... */
|
||||
estate.toread = shdr[symstrindex].sh_size;
|
||||
|
||||
if (estate.toread)
|
||||
{
|
||||
#if ELF_DEBUG
|
||||
printf("db str, size %lX, curaddr %lX\n",
|
||||
estate.toread, estate.curaddr);
|
||||
#endif
|
||||
/* Save where we are loading this... */
|
||||
symstr_load = estate.curaddr;
|
||||
|
||||
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
|
||||
estate.curaddr += sizeof(long);
|
||||
|
||||
/* Start to read... */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* all done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elf_freebsd_boot(unsigned long entry)
|
||||
{
|
||||
if (image_type != Elf_FreeBSD)
|
||||
return;
|
||||
|
||||
memset(&bsdinfo, 0, sizeof(bsdinfo));
|
||||
bsdinfo.bi_basemem = meminfo.basememsize;
|
||||
bsdinfo.bi_extmem = meminfo.memsize;
|
||||
bsdinfo.bi_memsizes_valid = 1;
|
||||
bsdinfo.bi_version = BOOTINFO_VERSION;
|
||||
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
|
||||
bsdinfo.bi_nfs_diskless = NULL;
|
||||
bsdinfo.bi_size = sizeof(bsdinfo);
|
||||
#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */
|
||||
if(freebsd_kernel_env[0] != '\0'){
|
||||
freebsd_howto |= RB_BOOTINFO;
|
||||
bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
|
||||
}
|
||||
|
||||
/* Check if we have symbols loaded, and if so,
|
||||
* made the meta_data needed to pass those to
|
||||
* the kernel. */
|
||||
if ((symtab_load !=0) && (symstr_load != 0))
|
||||
{
|
||||
unsigned long *t;
|
||||
|
||||
bsdinfo.bi_symtab = symtab_load;
|
||||
|
||||
/* End of symbols (long aligned...) */
|
||||
/* Assumes size of long is a power of 2... */
|
||||
bsdinfo.bi_esymtab = (symstr_load +
|
||||
sizeof(long) +
|
||||
*((long *)phys_to_virt(symstr_load)) +
|
||||
sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||
|
||||
/* Where we will build the meta data... */
|
||||
t = phys_to_virt(bsdinfo.bi_esymtab);
|
||||
|
||||
#if ELF_DEBUG
|
||||
printf("Metadata at %lX\n",t);
|
||||
#endif
|
||||
|
||||
/* Set up the pointer to the memory... */
|
||||
bsdinfo.bi_modulep = virt_to_phys(t);
|
||||
|
||||
/* The metadata structure is an array of 32-bit
|
||||
* words where we store some information about the
|
||||
* system. This is critical, as FreeBSD now looks
|
||||
* only for the metadata for the extended symbol
|
||||
* information rather than in the bootinfo.
|
||||
*/
|
||||
/* First, do the kernel name and the kernel type */
|
||||
/* Note that this assumed x86 byte order... */
|
||||
|
||||
/* 'kernel\0\0' */
|
||||
*t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
|
||||
|
||||
/* 'elf kernel\0\0' */
|
||||
*t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
|
||||
|
||||
/* Now the symbol start/end - note that they are
|
||||
* here in local/physical address - the Kernel
|
||||
* boot process will relocate the addresses. */
|
||||
*t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
|
||||
*t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
|
||||
|
||||
*t++=MODINFO_END; *t++=0; /* end of metadata */
|
||||
|
||||
/* Since we have symbols we need to make
|
||||
* sure that the kernel knows its own end
|
||||
* of memory... It is not _end but after
|
||||
* the symbols and the metadata... */
|
||||
bsdinfo.bi_kernend = virt_to_phys(t);
|
||||
|
||||
/* Signal locore.s that we have a valid bootinfo
|
||||
* structure that was completely filled in. */
|
||||
freebsd_howto |= 0x80000000;
|
||||
}
|
||||
|
||||
xstart32(entry, freebsd_howto, NODEV, 0, 0, 0,
|
||||
virt_to_phys(&bsdinfo), 0, 0, 0);
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AOUT_IMAGE
|
||||
static void aout_freebsd_probe(void)
|
||||
{
|
||||
image_type = Aout;
|
||||
if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
|
||||
/* Some other a.out variants have a different
|
||||
* value, and use other alignments (e.g. 1K),
|
||||
* not the 4K used by FreeBSD. */
|
||||
image_type = Aout_FreeBSD;
|
||||
printf("/FreeBSD");
|
||||
off = -(astate.head.a_entry & 0xff000000);
|
||||
astate.head.a_entry += off;
|
||||
}
|
||||
}
|
||||
|
||||
static void aout_freebsd_boot(void)
|
||||
{
|
||||
if (image_type == Aout_FreeBSD) {
|
||||
memset(&bsdinfo, 0, sizeof(bsdinfo));
|
||||
bsdinfo.bi_basemem = meminfo.basememsize;
|
||||
bsdinfo.bi_extmem = meminfo.memsize;
|
||||
bsdinfo.bi_memsizes_valid = 1;
|
||||
bsdinfo.bi_version = BOOTINFO_VERSION;
|
||||
bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
|
||||
bsdinfo.bi_nfs_diskless = NULL;
|
||||
bsdinfo.bi_size = sizeof(bsdinfo);
|
||||
xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0,
|
||||
virt_to_phys(&bsdinfo), 0, 0, 0);
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/init.h>
|
||||
@@ -189,19 +190,25 @@ static int initrd_init ( void ) {
|
||||
initrd_phys, ( initrd_phys + initrd_len ) );
|
||||
|
||||
/* Allocate image */
|
||||
image = alloc_image();
|
||||
image = alloc_image ( NULL );
|
||||
if ( ! image ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate image for "
|
||||
"initrd\n" );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_image;
|
||||
}
|
||||
image_set_name ( image, "<INITRD>" );
|
||||
if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not set image name: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_set_name;
|
||||
}
|
||||
|
||||
/* Allocate and copy initrd content */
|
||||
image->data = umalloc ( initrd_len );
|
||||
if ( ! image->data ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
|
||||
DBGC ( colour, "RUNTIME could not allocate %d bytes for "
|
||||
"initrd\n", initrd_len );
|
||||
rc = -ENOMEM;
|
||||
goto err_umalloc;
|
||||
}
|
||||
image->len = initrd_len;
|
||||
@@ -225,6 +232,7 @@ static int initrd_init ( void ) {
|
||||
|
||||
err_register_image:
|
||||
err_umalloc:
|
||||
err_set_name:
|
||||
image_put ( image );
|
||||
err_alloc_image:
|
||||
return rc;
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
#include <ipxe/console.h>
|
||||
#include <ipxe/init.h>
|
||||
#include "vga.h"
|
||||
#include <config/console.h>
|
||||
|
||||
/* Set default console usage if applicable */
|
||||
#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \
|
||||
CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) )
|
||||
#undef CONSOLE_DIRECT_VGA
|
||||
#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
|
||||
#endif
|
||||
|
||||
struct console_driver vga_console __console_driver;
|
||||
|
||||
@@ -97,6 +105,7 @@ static void vga_putc(int byte)
|
||||
struct console_driver vga_console __console_driver = {
|
||||
.putchar = vga_putc,
|
||||
.disabled = 1,
|
||||
.usage = CONSOLE_DIRECT_VGA,
|
||||
};
|
||||
|
||||
struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
#define LOAD_DEBUG 0
|
||||
|
||||
static int get_x_header(unsigned char *data, unsigned long now);
|
||||
static void jump_2ep();
|
||||
static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',};
|
||||
static char ** ep;
|
||||
|
||||
#define BOOT_ARG_PTR_LOCATION 0x001FFFFC
|
||||
|
||||
typedef struct _BOOT_ARGS{
|
||||
unsigned char ucVideoMode;
|
||||
unsigned char ucComPort;
|
||||
unsigned char ucBaudDivisor;
|
||||
unsigned char ucPCIConfigType;
|
||||
|
||||
unsigned long dwSig;
|
||||
#define BOOTARG_SIG 0x544F4F42
|
||||
unsigned long dwLen;
|
||||
|
||||
unsigned char ucLoaderFlags;
|
||||
unsigned char ucEshellFlags;
|
||||
unsigned char ucEdbgAdapterType;
|
||||
unsigned char ucEdbgIRQ;
|
||||
|
||||
unsigned long dwEdbgBaseAddr;
|
||||
unsigned long dwEdbgDebugZone;
|
||||
unsigned long dwDHCPLeaseTime;
|
||||
unsigned long dwEdbgFlags;
|
||||
|
||||
unsigned long dwEBootFlag;
|
||||
unsigned long dwEBootAddr;
|
||||
unsigned long dwLaunchAddr;
|
||||
|
||||
unsigned long pvFlatFrameBuffer;
|
||||
unsigned short vesaMode;
|
||||
unsigned short cxDisplayScreen;
|
||||
unsigned short cyDisplayScreen;
|
||||
unsigned short cxPhysicalScreen;
|
||||
unsigned short cyPhysicalScreen;
|
||||
unsigned short cbScanLineLength;
|
||||
unsigned short bppScreen;
|
||||
|
||||
unsigned char RedMaskSize;
|
||||
unsigned char REdMaskPosition;
|
||||
unsigned char GreenMaskSize;
|
||||
unsigned char GreenMaskPosition;
|
||||
unsigned char BlueMaskSize;
|
||||
unsigned char BlueMaskPosition;
|
||||
} BOOT_ARGS;
|
||||
|
||||
BOOT_ARGS BootArgs;
|
||||
|
||||
static struct segment_info{
|
||||
unsigned long addr; // Section Address
|
||||
unsigned long size; // Section Size
|
||||
unsigned long checksum; // Section CheckSum
|
||||
} X;
|
||||
|
||||
#define PSIZE (1500) //Max Packet Size
|
||||
#define DSIZE (PSIZE+12)
|
||||
static unsigned long dbuffer_available =0;
|
||||
static unsigned long not_loadin =0;
|
||||
static unsigned long d_now =0;
|
||||
|
||||
unsigned long entry;
|
||||
static unsigned long ce_curaddr;
|
||||
|
||||
|
||||
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof);
|
||||
static os_download_t wince_probe(unsigned char *data, unsigned int len)
|
||||
{
|
||||
if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
printf("(WINCE)");
|
||||
return ce_loader;
|
||||
}
|
||||
|
||||
static sector_t ce_loader(unsigned char *data, unsigned int len, int eof)
|
||||
{
|
||||
static unsigned char dbuffer[DSIZE];
|
||||
int this_write = 0;
|
||||
static int firsttime = 1;
|
||||
|
||||
/*
|
||||
* new packet in, we have to
|
||||
* [1] copy data to dbuffer,
|
||||
*
|
||||
* update...
|
||||
* [2] dbuffer_available
|
||||
*/
|
||||
memcpy( (dbuffer+dbuffer_available), data, len); //[1]
|
||||
dbuffer_available += len; // [2]
|
||||
len = 0;
|
||||
|
||||
d_now = 0;
|
||||
|
||||
#if 0
|
||||
printf("dbuffer_available =%ld \n", dbuffer_available);
|
||||
#endif
|
||||
|
||||
if (firsttime)
|
||||
{
|
||||
d_now = sizeof(ce_signature);
|
||||
printf("String Physical Address = %lx \n",
|
||||
*(unsigned long *)(dbuffer+d_now));
|
||||
|
||||
d_now += sizeof(unsigned long);
|
||||
printf("Image Size = %ld [%lx]\n",
|
||||
*(unsigned long *)(dbuffer+d_now),
|
||||
*(unsigned long *)(dbuffer+d_now));
|
||||
|
||||
d_now += sizeof(unsigned long);
|
||||
dbuffer_available -= d_now;
|
||||
|
||||
d_now = (unsigned long)get_x_header(dbuffer, d_now);
|
||||
firsttime = 0;
|
||||
}
|
||||
|
||||
if (not_loadin == 0)
|
||||
{
|
||||
d_now = get_x_header(dbuffer, d_now);
|
||||
}
|
||||
|
||||
while ( not_loadin > 0 )
|
||||
{
|
||||
/* dbuffer do not have enough data to loading, copy all */
|
||||
#if LOAD_DEBUG
|
||||
printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n",
|
||||
not_loadin, dbuffer_available);
|
||||
printf("[0] d_now = [%ld] \n", d_now);
|
||||
#endif
|
||||
|
||||
if( dbuffer_available <= not_loadin)
|
||||
{
|
||||
this_write = dbuffer_available ;
|
||||
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write );
|
||||
ce_curaddr += this_write;
|
||||
not_loadin -= this_write;
|
||||
|
||||
/* reset index and available in the dbuffer */
|
||||
dbuffer_available = 0;
|
||||
d_now = 0;
|
||||
#if LOAD_DEBUG
|
||||
printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n",
|
||||
not_loadin, dbuffer_available);
|
||||
printf("[1] d_now = [%ld], this_write = [%d] \n",
|
||||
d_now, this_write);
|
||||
#endif
|
||||
|
||||
// get the next packet...
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* dbuffer have more data then loading ... , copy partital.... */
|
||||
else
|
||||
{
|
||||
this_write = not_loadin;
|
||||
memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write);
|
||||
ce_curaddr += this_write;
|
||||
not_loadin = 0;
|
||||
|
||||
/* reset index and available in the dbuffer */
|
||||
dbuffer_available -= this_write;
|
||||
d_now += this_write;
|
||||
#if LOAD_DEBUG
|
||||
printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n",
|
||||
not_loadin, dbuffer_available);
|
||||
printf("[2] d_now = [%ld], this_write = [%d] \n\n",
|
||||
d_now, this_write);
|
||||
#endif
|
||||
|
||||
/* dbuffer not empty, proceed processing... */
|
||||
|
||||
// don't have enough data to get_x_header..
|
||||
if ( dbuffer_available < (sizeof(unsigned long) * 3) )
|
||||
{
|
||||
// printf("we don't have enough data remaining to call get_x. \n");
|
||||
memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOAD_DEBUG
|
||||
printf("with remaining data to call get_x \n");
|
||||
printf("dbuffer available = %ld , d_now = %ld\n",
|
||||
dbuffer_available, d_now);
|
||||
#endif
|
||||
d_now = get_x_header(dbuffer, d_now);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int get_x_header(unsigned char *dbuffer, unsigned long now)
|
||||
{
|
||||
X.addr = *(unsigned long *)(dbuffer + now);
|
||||
X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long));
|
||||
X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2);
|
||||
|
||||
if (X.addr == 0)
|
||||
{
|
||||
entry = X.size;
|
||||
done(1);
|
||||
printf("Entry Point Address = [%lx] \n", entry);
|
||||
jump_2ep();
|
||||
}
|
||||
|
||||
if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) {
|
||||
longjmp(restart_etherboot, -2);
|
||||
}
|
||||
|
||||
ce_curaddr = X.addr;
|
||||
now += sizeof(unsigned long)*3;
|
||||
|
||||
/* re-calculate dbuffer available... */
|
||||
dbuffer_available -= sizeof(unsigned long)*3;
|
||||
|
||||
/* reset index of this section */
|
||||
not_loadin = X.size;
|
||||
|
||||
#if 1
|
||||
printf("\n");
|
||||
printf("\t Section Address = [%lx] \n", X.addr);
|
||||
printf("\t Size = %d [%lx]\n", X.size, X.size);
|
||||
printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum);
|
||||
#endif
|
||||
#if LOAD_DEBUG
|
||||
printf("____________________________________________\n");
|
||||
printf("\t dbuffer_now = %ld \n", now);
|
||||
printf("\t dbuffer available = %ld \n", dbuffer_available);
|
||||
printf("\t not_loadin = %ld \n", not_loadin);
|
||||
#endif
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
static void jump_2ep()
|
||||
{
|
||||
BootArgs.ucVideoMode = 1;
|
||||
BootArgs.ucComPort = 1;
|
||||
BootArgs.ucBaudDivisor = 1;
|
||||
BootArgs.ucPCIConfigType = 1; // do not fill with 0
|
||||
|
||||
BootArgs.dwSig = BOOTARG_SIG;
|
||||
BootArgs.dwLen = sizeof(BootArgs);
|
||||
|
||||
if(BootArgs.ucVideoMode == 0)
|
||||
{
|
||||
BootArgs.cxDisplayScreen = 640;
|
||||
BootArgs.cyDisplayScreen = 480;
|
||||
BootArgs.cxPhysicalScreen = 640;
|
||||
BootArgs.cyPhysicalScreen = 480;
|
||||
BootArgs.bppScreen = 16;
|
||||
BootArgs.cbScanLineLength = 1024;
|
||||
BootArgs.pvFlatFrameBuffer = 0x800a0000; // ollie say 0x98000000
|
||||
}
|
||||
else if(BootArgs.ucVideoMode != 0xFF)
|
||||
{
|
||||
BootArgs.cxDisplayScreen = 0;
|
||||
BootArgs.cyDisplayScreen = 0;
|
||||
BootArgs.cxPhysicalScreen = 0;
|
||||
BootArgs.cyPhysicalScreen = 0;
|
||||
BootArgs.bppScreen = 0;
|
||||
BootArgs.cbScanLineLength = 0;
|
||||
BootArgs.pvFlatFrameBuffer = 0;
|
||||
}
|
||||
|
||||
ep = phys_to_virt(BOOT_ARG_PTR_LOCATION);
|
||||
*ep= virt_to_phys(&BootArgs);
|
||||
xstart32(entry);
|
||||
}
|
||||
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <byteswap.h>
|
||||
#include <pxe.h>
|
||||
#include <realmode.h>
|
||||
#include <pic8259.h>
|
||||
@@ -166,6 +167,10 @@ static int undinet_isr_triggered ( void ) {
|
||||
static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
|
||||
#define undinet_tbd __use_data16 ( undinet_tbd )
|
||||
|
||||
/** UNDI transmit destination address */
|
||||
static uint8_t __data16_array ( undinet_destaddr, [ETH_ALEN] );
|
||||
#define undinet_destaddr __use_data16 ( undinet_destaddr )
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
@@ -175,8 +180,14 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
|
||||
*/
|
||||
static int undinet_transmit ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf ) {
|
||||
struct undi_nic *undinic = netdev->priv;
|
||||
struct s_PXENV_UNDI_TRANSMIT undi_transmit;
|
||||
size_t len = iob_len ( iobuf );
|
||||
const void *ll_dest;
|
||||
const void *ll_source;
|
||||
uint16_t net_proto;
|
||||
unsigned int flags;
|
||||
uint8_t protocol;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Technically, we ought to make sure that the previous
|
||||
@@ -189,15 +200,49 @@ static int undinet_transmit ( struct net_device *netdev,
|
||||
* transmit the next packet.
|
||||
*/
|
||||
|
||||
/* Some PXE stacks are unable to cope with P_UNKNOWN, and will
|
||||
* always try to prepend a link-layer header. Work around
|
||||
* these stacks by stripping the existing link-layer header
|
||||
* and allowing the PXE stack to (re)construct the link-layer
|
||||
* header itself.
|
||||
*/
|
||||
if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
|
||||
&net_proto, &flags ) ) != 0 ) {
|
||||
DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
|
||||
"%s\n", undinic, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
|
||||
switch ( net_proto ) {
|
||||
case htons ( ETH_P_IP ) :
|
||||
protocol = P_IP;
|
||||
break;
|
||||
case htons ( ETH_P_ARP ) :
|
||||
protocol = P_ARP;
|
||||
break;
|
||||
case htons ( ETH_P_RARP ) :
|
||||
protocol = P_RARP;
|
||||
break;
|
||||
default:
|
||||
/* Unknown protocol; restore the original link-layer header */
|
||||
iob_push ( iobuf, sizeof ( struct ethhdr ) );
|
||||
protocol = P_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy packet to UNDI I/O buffer */
|
||||
len = iob_len ( iobuf );
|
||||
if ( len > sizeof ( basemem_packet ) )
|
||||
len = sizeof ( basemem_packet );
|
||||
memcpy ( &basemem_packet, iobuf->data, len );
|
||||
|
||||
/* Create PXENV_UNDI_TRANSMIT data structure */
|
||||
memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
|
||||
undi_transmit.Protocol = protocol;
|
||||
undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
|
||||
XMT_BROADCAST : XMT_DESTADDR );
|
||||
undi_transmit.DestAddr.segment = rm_ds;
|
||||
undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd );
|
||||
undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
|
||||
undi_transmit.TBD.segment = rm_ds;
|
||||
undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/console.h>
|
||||
#include <ipxe/ansiesc.h>
|
||||
#include <ipxe/keymap.h>
|
||||
#include <config/console.h>
|
||||
|
||||
#define ATTR_BOLD 0x08
|
||||
|
||||
@@ -48,6 +49,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#define ATTR_DEFAULT ATTR_FCOL_WHITE
|
||||
|
||||
/* Set default console usage if applicable */
|
||||
#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
|
||||
#undef CONSOLE_PCBIOS
|
||||
#define CONSOLE_PCBIOS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
|
||||
#endif
|
||||
|
||||
/** Current character attribute */
|
||||
static unsigned int bios_attr = ATTR_DEFAULT;
|
||||
|
||||
@@ -163,6 +170,14 @@ static void bios_putchar ( int character ) {
|
||||
/* Skip non-printable characters */
|
||||
"cmpb $0x20, %%al\n\t"
|
||||
"jb 1f\n\t"
|
||||
/* Read attribute */
|
||||
"movb %%al, %%cl\n\t"
|
||||
"movb $0x08, %%ah\n\t"
|
||||
"int $0x10\n\t"
|
||||
"xchgb %%al, %%cl\n\t"
|
||||
/* Skip if attribute matches */
|
||||
"cmpb %%ah, %%bl\n\t"
|
||||
"je 1f\n\t"
|
||||
/* Set attribute */
|
||||
"movw $0x0001, %%cx\n\t"
|
||||
"movb $0x09, %%ah\n\t"
|
||||
@@ -201,6 +216,8 @@ static const char ansi_sequences[] = {
|
||||
BIOS_KEY ( "\x4d", "[C" ) /* Right arrow */
|
||||
BIOS_KEY ( "\x47", "[H" ) /* Home */
|
||||
BIOS_KEY ( "\x4f", "[F" ) /* End */
|
||||
BIOS_KEY ( "\x49", "[5~" ) /* Page up */
|
||||
BIOS_KEY ( "\x51", "[6~" ) /* Page down */
|
||||
BIOS_KEY ( "\x3f", "[15~" ) /* F5 */
|
||||
BIOS_KEY ( "\x40", "[17~" ) /* F6 */
|
||||
BIOS_KEY ( "\x41", "[18~" ) /* F7 */
|
||||
@@ -311,4 +328,5 @@ struct console_driver bios_console __console_driver = {
|
||||
.putchar = bios_putchar,
|
||||
.getchar = bios_getchar,
|
||||
.iskey = bios_iskey,
|
||||
.usage = CONSOLE_PCBIOS,
|
||||
};
|
||||
|
||||
@@ -42,10 +42,11 @@ FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
|
||||
*/
|
||||
static int elfboot_exec ( struct image *image ) {
|
||||
physaddr_t entry;
|
||||
physaddr_t max;
|
||||
int rc;
|
||||
|
||||
/* Load the image using core ELF support */
|
||||
if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
|
||||
if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) {
|
||||
DBGC ( image, "ELF %p could not load: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
|
||||
@@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/elf.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/features.h>
|
||||
#include <ipxe/uri.h>
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
|
||||
|
||||
@@ -139,53 +140,60 @@ static void multiboot_build_memmap ( struct image *image,
|
||||
/**
|
||||
* Add command line in base memory
|
||||
*
|
||||
* @v imgname Image name
|
||||
* @v cmdline Command line
|
||||
* @v image Image
|
||||
* @ret physaddr Physical address of command line
|
||||
*/
|
||||
physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) {
|
||||
char *mb_cmdline;
|
||||
static physaddr_t multiboot_add_cmdline ( struct image *image ) {
|
||||
char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
|
||||
size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset );
|
||||
char *buf = mb_cmdline;
|
||||
size_t len;
|
||||
|
||||
if ( ! cmdline )
|
||||
cmdline = "";
|
||||
/* Copy image URI to base memory buffer as start of command line */
|
||||
len = ( unparse_uri ( buf, remaining, image->uri,
|
||||
URI_ALL ) + 1 /* NUL */ );
|
||||
if ( len > remaining )
|
||||
len = remaining;
|
||||
mb_cmdline_offset += len;
|
||||
buf += len;
|
||||
remaining -= len;
|
||||
|
||||
/* Copy command line to base memory buffer */
|
||||
mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
|
||||
mb_cmdline_offset +=
|
||||
( snprintf ( mb_cmdline,
|
||||
( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
|
||||
"%s %s", imgname, cmdline ) + 1 );
|
||||
|
||||
/* Truncate to terminating NUL in buffer if necessary */
|
||||
if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
|
||||
mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
|
||||
/* Copy command line to base memory buffer, if present */
|
||||
if ( image->cmdline ) {
|
||||
mb_cmdline_offset--; /* Strip NUL */
|
||||
buf--;
|
||||
remaining++;
|
||||
len = ( snprintf ( buf, remaining, " %s",
|
||||
image->cmdline ) + 1 /* NUL */ );
|
||||
if ( len > remaining )
|
||||
len = remaining;
|
||||
mb_cmdline_offset += len;
|
||||
}
|
||||
|
||||
return virt_to_phys ( mb_cmdline );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build multiboot module list
|
||||
* Add multiboot modules
|
||||
*
|
||||
* @v image Multiboot image
|
||||
* @v modules Module list to fill, or NULL
|
||||
* @ret count Number of modules
|
||||
* @v start Start address for modules
|
||||
* @v mbinfo Multiboot information structure
|
||||
* @v modules Multiboot module list
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static unsigned int
|
||||
multiboot_build_module_list ( struct image *image,
|
||||
struct multiboot_module *modules,
|
||||
unsigned int limit ) {
|
||||
static int multiboot_add_modules ( struct image *image, physaddr_t start,
|
||||
struct multiboot_info *mbinfo,
|
||||
struct multiboot_module *modules,
|
||||
unsigned int limit ) {
|
||||
struct image *module_image;
|
||||
struct multiboot_module *module;
|
||||
unsigned int count = 0;
|
||||
unsigned int insert;
|
||||
physaddr_t start;
|
||||
physaddr_t end;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Add each image as a multiboot module */
|
||||
for_each_image ( module_image ) {
|
||||
|
||||
if ( count >= limit ) {
|
||||
if ( mbinfo->mods_count >= limit ) {
|
||||
DBGC ( image, "MULTIBOOT %p limit of %d modules "
|
||||
"reached\n", image, limit );
|
||||
break;
|
||||
@@ -195,38 +203,36 @@ multiboot_build_module_list ( struct image *image,
|
||||
if ( module_image == image )
|
||||
continue;
|
||||
|
||||
/* At least some OSes expect the multiboot modules to
|
||||
* be in ascending order, so we have to support it.
|
||||
*/
|
||||
start = user_to_phys ( module_image->data, 0 );
|
||||
end = user_to_phys ( module_image->data, module_image->len );
|
||||
for ( insert = 0 ; insert < count ; insert++ ) {
|
||||
if ( start < modules[insert].mod_start )
|
||||
break;
|
||||
/* Page-align the module */
|
||||
start = ( ( start + 0xfff ) & ~0xfff );
|
||||
|
||||
/* Prepare segment */
|
||||
if ( ( rc = prep_segment ( phys_to_user ( start ),
|
||||
module_image->len,
|
||||
module_image->len ) ) != 0 ) {
|
||||
DBGC ( image, "MULTIBOOT %p could not prepare module "
|
||||
"%s: %s\n", image, module_image->name,
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
module = &modules[insert];
|
||||
memmove ( ( module + 1 ), module,
|
||||
( ( count - insert ) * sizeof ( *module ) ) );
|
||||
|
||||
/* Copy module */
|
||||
memcpy_user ( phys_to_user ( start ), 0,
|
||||
module_image->data, 0, module_image->len );
|
||||
|
||||
/* Add module to list */
|
||||
module = &modules[mbinfo->mods_count++];
|
||||
module->mod_start = start;
|
||||
module->mod_end = end;
|
||||
module->string = multiboot_add_cmdline ( module_image->name,
|
||||
module_image->cmdline );
|
||||
module->mod_end = ( start + module_image->len );
|
||||
module->string = multiboot_add_cmdline ( module_image );
|
||||
module->reserved = 0;
|
||||
|
||||
/* We promise to page-align modules */
|
||||
assert ( ( module->mod_start & 0xfff ) == 0 );
|
||||
|
||||
count++;
|
||||
DBGC ( image, "MULTIBOOT %p module %s is [%x,%x)\n",
|
||||
image, module_image->name, module->mod_start,
|
||||
module->mod_end );
|
||||
start += module_image->len;
|
||||
}
|
||||
|
||||
/* Dump module configuration */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
|
||||
image, i, modules[i].mod_start,
|
||||
modules[i].mod_end );
|
||||
}
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,11 +311,12 @@ static int multiboot_find_header ( struct image *image,
|
||||
* @v image Multiboot file
|
||||
* @v hdr Multiboot header descriptor
|
||||
* @ret entry Entry point
|
||||
* @ret max Maximum used address
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_load_raw ( struct image *image,
|
||||
struct multiboot_header_info *hdr,
|
||||
physaddr_t *entry ) {
|
||||
physaddr_t *entry, physaddr_t *max ) {
|
||||
size_t offset;
|
||||
size_t filesz;
|
||||
size_t memsz;
|
||||
@@ -340,8 +347,9 @@ static int multiboot_load_raw ( struct image *image,
|
||||
/* Copy image to segment */
|
||||
memcpy_user ( buffer, 0, image->data, offset, filesz );
|
||||
|
||||
/* Record execution entry point */
|
||||
/* Record execution entry point and maximum used address */
|
||||
*entry = hdr->mb.entry_addr;
|
||||
*max = ( hdr->mb.load_addr + memsz );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -351,13 +359,15 @@ static int multiboot_load_raw ( struct image *image,
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @ret entry Entry point
|
||||
* @ret max Maximum used address
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
|
||||
static int multiboot_load_elf ( struct image *image, physaddr_t *entry,
|
||||
physaddr_t *max ) {
|
||||
int rc;
|
||||
|
||||
/* Load ELF image*/
|
||||
if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
|
||||
if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) {
|
||||
DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
@@ -375,6 +385,7 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
|
||||
static int multiboot_exec ( struct image *image ) {
|
||||
struct multiboot_header_info hdr;
|
||||
physaddr_t entry;
|
||||
physaddr_t max;
|
||||
int rc;
|
||||
|
||||
/* Locate multiboot header, if present */
|
||||
@@ -396,8 +407,8 @@ static int multiboot_exec ( struct image *image ) {
|
||||
* the ELF header if present, and Solaris relies on this
|
||||
* behaviour.
|
||||
*/
|
||||
if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
|
||||
( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
|
||||
if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) &&
|
||||
( ( rc = multiboot_load_raw ( image, &hdr, &entry, &max ) ) != 0 ))
|
||||
return rc;
|
||||
|
||||
/* Populate multiboot information structure */
|
||||
@@ -405,12 +416,14 @@ static int multiboot_exec ( struct image *image ) {
|
||||
mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
|
||||
MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
|
||||
mb_cmdline_offset = 0;
|
||||
mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
|
||||
mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
|
||||
( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
|
||||
mbinfo.cmdline = multiboot_add_cmdline ( image );
|
||||
mbinfo.mods_addr = virt_to_phys ( mbmodules );
|
||||
mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
|
||||
mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
|
||||
if ( ( rc = multiboot_add_modules ( image, max, &mbinfo, mbmodules,
|
||||
( sizeof ( mbmodules ) /
|
||||
sizeof ( mbmodules[0] ) ) ) ) !=0)
|
||||
return rc;
|
||||
|
||||
/* Multiboot images may not return and have no callback
|
||||
* interface, so shut everything down prior to booting the OS.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#define BDA_SEG 0x0040
|
||||
#define BDA_EQUIPMENT_WORD 0x0010
|
||||
#define BDA_FBMS 0x0013
|
||||
#define BDA_NUM_DRIVES 0x0075
|
||||
|
||||
|
||||
@@ -1,43 +1,70 @@
|
||||
#ifndef ETHERBOOT_BITS_BYTESWAP_H
|
||||
#define ETHERBOOT_BITS_BYTESWAP_H
|
||||
#ifndef _BITS_BYTESWAP_H
|
||||
#define _BITS_BYTESWAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Byte-order swapping functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
static inline __attribute__ ((always_inline, const)) uint16_t
|
||||
__bswap_variable_16(uint16_t x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0\n\t"
|
||||
: "=q" (x)
|
||||
: "0" (x));
|
||||
static inline __attribute__ (( always_inline, const )) uint16_t
|
||||
__bswap_variable_16 ( uint16_t x ) {
|
||||
__asm__ ( "xchgb %b0,%h0" : "=q" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ ((always_inline, const)) uint32_t
|
||||
__bswap_variable_32(uint32_t x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0\n\t"
|
||||
"rorl $16,%0\n\t"
|
||||
"xchgb %b0,%h0"
|
||||
: "=q" (x)
|
||||
: "0" (x));
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_16s ( uint16_t *x ) {
|
||||
__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint32_t
|
||||
__bswap_variable_32 ( uint32_t x ) {
|
||||
__asm__ ( "bswapl %0" : "=r" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ ((always_inline, const)) uint64_t
|
||||
__bswap_variable_64(uint64_t x)
|
||||
{
|
||||
union {
|
||||
uint64_t qword;
|
||||
uint32_t dword[2];
|
||||
} u;
|
||||
|
||||
u.qword = x;
|
||||
u.dword[0] = __bswap_variable_32(u.dword[0]);
|
||||
u.dword[1] = __bswap_variable_32(u.dword[1]);
|
||||
__asm__("xchgl %0,%1"
|
||||
: "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
|
||||
: "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
|
||||
return u.qword;
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_32s ( uint32_t *x ) {
|
||||
__asm__ ( "bswapl %0" : "=r" ( *x ) : "0" ( *x ) );
|
||||
}
|
||||
|
||||
#endif /* ETHERBOOT_BITS_BYTESWAP_H */
|
||||
static inline __attribute__ (( always_inline, const )) uint64_t
|
||||
__bswap_variable_64 ( uint64_t x ) {
|
||||
uint32_t in_high = ( x >> 32 );
|
||||
uint32_t in_low = ( x & 0xffffffffUL );
|
||||
uint32_t out_high;
|
||||
uint32_t out_low;
|
||||
|
||||
__asm__ ( "bswapl %0\n\t"
|
||||
"bswapl %1\n\t"
|
||||
"xchgl %0,%1\n\t"
|
||||
: "=r" ( out_high ), "=r" ( out_low )
|
||||
: "0" ( in_high ), "1" ( in_low ) );
|
||||
|
||||
return ( ( ( ( uint64_t ) out_high ) << 32 ) |
|
||||
( ( uint64_t ) out_low ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_64s ( uint64_t *x ) {
|
||||
struct {
|
||||
uint32_t low;
|
||||
uint32_t high;
|
||||
} __attribute__ (( may_alias )) *dwords = ( ( void * ) x );
|
||||
uint32_t discard;
|
||||
|
||||
__asm__ ( "movl %0,%2\n\t"
|
||||
"bswapl %2\n\t"
|
||||
"xchgl %2,%1\n\t"
|
||||
"bswapl %2\n\t"
|
||||
"movl %2,%0\n\t"
|
||||
: "+m" ( dwords->low ), "+m" ( dwords->high ),
|
||||
"=r" ( discard ) );
|
||||
}
|
||||
|
||||
#endif /* _BITS_BYTESWAP_H */
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_ENTROPY_H
|
||||
#define _BITS_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/rtc_entropy.h>
|
||||
|
||||
#endif /* _BITS_ENTROPY_H */
|
||||
@@ -16,6 +16,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
|
||||
#define ERRFILE_pxeparent ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
|
||||
#define ERRFILE_runtime ( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 )
|
||||
#define ERRFILE_vmware ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 )
|
||||
#define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 )
|
||||
#define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 )
|
||||
|
||||
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
|
||||
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_TIME_H
|
||||
#define _BITS_TIME_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific time API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <ipxe/rtc_time.h>
|
||||
|
||||
#endif /* _BITS_TIME_H */
|
||||
@@ -71,6 +71,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
/** Block size for non-extended INT 13 calls */
|
||||
#define INT13_BLKSIZE 512
|
||||
|
||||
/** @defgroup int13fddtype INT 13 floppy disk drive types
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** 360K */
|
||||
#define INT13_FDD_TYPE_360K 0x01
|
||||
/** 1.2M */
|
||||
#define INT13_FDD_TYPE_1M2 0x02
|
||||
/** 720K */
|
||||
#define INT13_FDD_TYPE_720K 0x03
|
||||
/** 1.44M */
|
||||
#define INT13_FDD_TYPE_1M44 0x04
|
||||
|
||||
/** An INT 13 disk address packet */
|
||||
struct int13_disk_address {
|
||||
/** Size of the packet, in bytes */
|
||||
@@ -394,4 +407,43 @@ enum eltorito_media_type {
|
||||
ELTORITO_NO_EMULATION = 0,
|
||||
};
|
||||
|
||||
/** A floppy disk geometry */
|
||||
struct int13_fdd_geometry {
|
||||
/** Number of tracks */
|
||||
uint8_t tracks;
|
||||
/** Number of heads and sectors per track */
|
||||
uint8_t heads_spt;
|
||||
};
|
||||
|
||||
/** Define a floppy disk geometry */
|
||||
#define INT13_FDD_GEOMETRY( cylinders, heads, sectors ) \
|
||||
{ \
|
||||
.tracks = (cylinders), \
|
||||
.heads_spt = ( ( (heads) << 6 ) | (sectors) ), \
|
||||
}
|
||||
|
||||
/** Get floppy disk number of cylinders */
|
||||
#define INT13_FDD_CYLINDERS( geometry ) ( (geometry)->tracks )
|
||||
|
||||
/** Get floppy disk number of heads */
|
||||
#define INT13_FDD_HEADS( geometry ) ( (geometry)->heads_spt >> 6 )
|
||||
|
||||
/** Get floppy disk number of sectors per track */
|
||||
#define INT13_FDD_SECTORS( geometry ) ( (geometry)->heads_spt & 0x3f )
|
||||
|
||||
/** A floppy drive parameter table */
|
||||
struct int13_fdd_parameters {
|
||||
uint8_t step_rate__head_unload;
|
||||
uint8_t head_load__ndma;
|
||||
uint8_t motor_off_delay;
|
||||
uint8_t bytes_per_sector;
|
||||
uint8_t sectors_per_track;
|
||||
uint8_t gap_length;
|
||||
uint8_t data_length;
|
||||
uint8_t format_gap_length;
|
||||
uint8_t format_filler;
|
||||
uint8_t head_settle_time;
|
||||
uint8_t motor_start_time;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
#endif /* INT13_H */
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef _IPXE_GUESTRPC_H
|
||||
#define _IPXE_GUESTRPC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VMware GuestRPC mechanism
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/vmware.h>
|
||||
|
||||
/** GuestRPC magic number */
|
||||
#define GUESTRPC_MAGIC 0x49435052 /* "RPCI" */
|
||||
|
||||
/** Open RPC channel */
|
||||
#define GUESTRPC_OPEN 0x00
|
||||
|
||||
/** Open RPC channel success status */
|
||||
#define GUESTRPC_OPEN_SUCCESS 0x00010000
|
||||
|
||||
/** Send RPC command length */
|
||||
#define GUESTRPC_COMMAND_LEN 0x01
|
||||
|
||||
/** Send RPC command length success status */
|
||||
#define GUESTRPC_COMMAND_LEN_SUCCESS 0x00810000
|
||||
|
||||
/** Send RPC command data */
|
||||
#define GUESTRPC_COMMAND_DATA 0x02
|
||||
|
||||
/** Send RPC command data success status */
|
||||
#define GUESTRPC_COMMAND_DATA_SUCCESS 0x00010000
|
||||
|
||||
/** Receive RPC reply length */
|
||||
#define GUESTRPC_REPLY_LEN 0x03
|
||||
|
||||
/** Receive RPC reply length success status */
|
||||
#define GUESTRPC_REPLY_LEN_SUCCESS 0x00830000
|
||||
|
||||
/** Receive RPC reply data */
|
||||
#define GUESTRPC_REPLY_DATA 0x04
|
||||
|
||||
/** Receive RPC reply data success status */
|
||||
#define GUESTRPC_REPLY_DATA_SUCCESS 0x00010000
|
||||
|
||||
/** Finish receiving RPC reply */
|
||||
#define GUESTRPC_REPLY_FINISH 0x05
|
||||
|
||||
/** Finish receiving RPC reply success status */
|
||||
#define GUESTRPC_REPLY_FINISH_SUCCESS 0x00010000
|
||||
|
||||
/** Close RPC channel */
|
||||
#define GUESTRPC_CLOSE 0x06
|
||||
|
||||
/** Close RPC channel success status */
|
||||
#define GUESTRPC_CLOSE_SUCCESS 0x00010000
|
||||
|
||||
/** RPC command success status */
|
||||
#define GUESTRPC_SUCCESS 0x2031 /* "1 " */
|
||||
|
||||
extern int guestrpc_open ( void );
|
||||
extern void guestrpc_close ( int channel );
|
||||
extern int guestrpc_command ( int channel, const char *command, char *reply,
|
||||
size_t reply_len );
|
||||
|
||||
#endif /* _IPXE_GUESTRPC_H */
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef _IPXE_RTC_ENTROPY_H
|
||||
#define _IPXE_RTC_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RTC-based entropy source
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ENTROPY_RTC
|
||||
#define ENTROPY_PREFIX_rtc
|
||||
#else
|
||||
#define ENTROPY_PREFIX_rtc __rtc_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* min-entropy per sample
|
||||
*
|
||||
* @ret min_entropy min-entropy of each sample
|
||||
*/
|
||||
static inline __always_inline double
|
||||
ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
|
||||
|
||||
/* The min-entropy has been measured on several platforms
|
||||
* using the entropy_sample test code. Modelling the samples
|
||||
* as independent, and using a confidence level of 99.99%, the
|
||||
* measurements were as follows:
|
||||
*
|
||||
* qemu-kvm : 7.38 bits
|
||||
* VMware : 7.46 bits
|
||||
* Physical hardware : 2.67 bits
|
||||
*
|
||||
* We choose the lowest of these (2.67 bits) and apply a 50%
|
||||
* safety margin to allow for some potential non-independence
|
||||
* of samples.
|
||||
*/
|
||||
return 1.3;
|
||||
}
|
||||
|
||||
extern uint8_t rtc_sample ( void );
|
||||
|
||||
/**
|
||||
* Get noise sample
|
||||
*
|
||||
* @ret noise Noise sample
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static inline __always_inline int
|
||||
ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
|
||||
|
||||
/* Get sample */
|
||||
*noise = rtc_sample();
|
||||
|
||||
/* Always successful */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_RTC_ENTROPY_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _IPXE_RTC_TIME_H
|
||||
#define _IPXE_RTC_TIME_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RTC-based time source
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifdef TIME_RTC
|
||||
#define TIME_PREFIX_rtc
|
||||
#else
|
||||
#define TIME_PREFIX_rtc __rtc_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_RTC_TIME_H */
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef _IPXE_VMWARE_H
|
||||
#define _IPXE_VMWARE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VMware backdoor mechanism
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** VMware backdoor I/O port */
|
||||
#define VMW_PORT 0x5658
|
||||
|
||||
/** VMware backdoor magic value */
|
||||
#define VMW_MAGIC 0x564d5868 /* "VMXh" */
|
||||
|
||||
/** VMware backdoor magic instruction */
|
||||
#define VMW_BACKDOOR "inl %%dx, %%eax"
|
||||
|
||||
/** Get VMware version */
|
||||
#define VMW_CMD_GET_VERSION 0x0a
|
||||
|
||||
/** Issue GuestRPC command */
|
||||
#define VMW_CMD_GUESTRPC 0x1e
|
||||
|
||||
/**
|
||||
* Get VMware version
|
||||
*
|
||||
* @ret version VMware version(?)
|
||||
* @ret magic VMware magic number, if present
|
||||
* @ret product_type VMware product type
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
vmware_cmd_get_version ( uint32_t *version, uint32_t *magic,
|
||||
uint32_t *product_type ) {
|
||||
uint32_t discard_d;
|
||||
|
||||
/* Perform backdoor call */
|
||||
__asm__ __volatile__ ( VMW_BACKDOOR
|
||||
: "=a" ( *version ), "=b" ( *magic ),
|
||||
"=c" ( *product_type ), "=d" ( discard_d )
|
||||
: "0" ( VMW_MAGIC ), "1" ( 0 ),
|
||||
"2" ( VMW_CMD_GET_VERSION ),
|
||||
"3" ( VMW_PORT ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue GuestRPC command
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @v subcommand GuestRPC subcommand
|
||||
* @v parameter Subcommand-specific parameter
|
||||
* @ret edxhi Subcommand-specific result
|
||||
* @ret ebx Subcommand-specific result
|
||||
* @ret status Command status
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) uint32_t
|
||||
vmware_cmd_guestrpc ( int channel, uint16_t subcommand, uint32_t parameter,
|
||||
uint16_t *edxhi, uint32_t *ebx ) {
|
||||
uint32_t discard_a;
|
||||
uint32_t status;
|
||||
uint32_t edx;
|
||||
|
||||
/* Perform backdoor call */
|
||||
__asm__ __volatile__ ( VMW_BACKDOOR
|
||||
: "=a" ( discard_a ), "=b" ( *ebx ),
|
||||
"=c" ( status ), "=d" ( edx )
|
||||
: "0" ( VMW_MAGIC ), "1" ( parameter ),
|
||||
"2" ( VMW_CMD_GUESTRPC | ( subcommand << 16 )),
|
||||
"3" ( VMW_PORT | ( channel << 16 ) ) );
|
||||
*edxhi = ( edx >> 16 );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
extern int vmware_present ( void );
|
||||
|
||||
#endif /* _IPXE_VMWARE_H */
|
||||
@@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#ifndef PIC8259_H
|
||||
#define PIC8259_H
|
||||
|
||||
#include <ipxe/io.h>
|
||||
|
||||
/* For segoff_t */
|
||||
#include "realmode.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifndef _RTC_H
|
||||
#define _RTC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* CMOS Real-Time Clock (RTC)
|
||||
*
|
||||
* The CMOS/RTC registers are documented (with varying degrees of
|
||||
* accuracy and consistency) at
|
||||
*
|
||||
* http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt
|
||||
* http://wiki.osdev.org/RTC
|
||||
* http://wiki.osdev.org/CMOS
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <pic8259.h>
|
||||
|
||||
/** RTC IRQ */
|
||||
#define RTC_IRQ 8
|
||||
|
||||
/** RTC interrupt vector */
|
||||
#define RTC_INT IRQ_INT ( RTC_IRQ )
|
||||
|
||||
/** CMOS/RTC address (and NMI) register */
|
||||
#define CMOS_ADDRESS 0x70
|
||||
|
||||
/** NMI disable bit */
|
||||
#define CMOS_DISABLE_NMI 0x80
|
||||
|
||||
/** CMOS/RTC data register */
|
||||
#define CMOS_DATA 0x71
|
||||
|
||||
/** RTC seconds */
|
||||
#define RTC_SEC 0x00
|
||||
|
||||
/** RTC minutes */
|
||||
#define RTC_MIN 0x02
|
||||
|
||||
/** RTC hours */
|
||||
#define RTC_HOUR 0x04
|
||||
|
||||
/** RTC weekday */
|
||||
#define RTC_WDAY 0x06
|
||||
|
||||
/** RTC day of month */
|
||||
#define RTC_MDAY 0x07
|
||||
|
||||
/** RTC month */
|
||||
#define RTC_MON 0x08
|
||||
|
||||
/** RTC year */
|
||||
#define RTC_YEAR 0x09
|
||||
|
||||
/** RTC status register A */
|
||||
#define RTC_STATUS_A 0x0a
|
||||
|
||||
/** RTC update in progress bit */
|
||||
#define RTC_STATUS_A_UPDATE_IN_PROGRESS 0x80
|
||||
|
||||
/** RTC status register B */
|
||||
#define RTC_STATUS_B 0x0b
|
||||
|
||||
/** RTC 24 hour format bit */
|
||||
#define RTC_STATUS_B_24_HOUR 0x02
|
||||
|
||||
/** RTC binary mode bit */
|
||||
#define RTC_STATUS_B_BINARY 0x04
|
||||
|
||||
/** RTC Periodic Interrupt Enabled bit */
|
||||
#define RTC_STATUS_B_PIE 0x40
|
||||
|
||||
/** RTC status register C */
|
||||
#define RTC_STATUS_C 0x0c
|
||||
|
||||
/** RTC status register D */
|
||||
#define RTC_STATUS_D 0x0d
|
||||
|
||||
/** CMOS default address */
|
||||
#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D
|
||||
|
||||
#endif /* _RTC_H */
|
||||
@@ -75,9 +75,9 @@ struct int13_drive {
|
||||
/** Underlying block device interface */
|
||||
struct interface block;
|
||||
|
||||
/** BIOS in-use drive number (0x80-0xff) */
|
||||
/** BIOS in-use drive number (0x00-0xff) */
|
||||
unsigned int drive;
|
||||
/** BIOS natural drive number (0x80-0xff)
|
||||
/** BIOS natural drive number (0x00-0xff)
|
||||
*
|
||||
* This is the drive number that would have been assigned by
|
||||
* 'naturally' appending the drive to the end of the BIOS
|
||||
@@ -142,17 +142,44 @@ static struct segoff __text16 ( int13_vector );
|
||||
/** Assembly wrapper */
|
||||
extern void int13_wrapper ( void );
|
||||
|
||||
/** Dummy floppy disk parameter table */
|
||||
static struct int13_fdd_parameters __data16 ( int13_fdd_params ) = {
|
||||
/* 512 bytes per sector */
|
||||
.bytes_per_sector = 0x02,
|
||||
/* Highest sectors per track that we ever return */
|
||||
.sectors_per_track = 48,
|
||||
};
|
||||
#define int13_fdd_params __use_data16 ( int13_fdd_params )
|
||||
|
||||
/** List of registered emulated drives */
|
||||
static LIST_HEAD ( int13s );
|
||||
|
||||
/**
|
||||
* Number of BIOS drives
|
||||
* Equipment word
|
||||
*
|
||||
* Note that this is the number of drives in the system as a whole
|
||||
* (i.e. a mirror of the counter at 40:75), rather than a count of the
|
||||
* number of emulated drives.
|
||||
* This is a cached copy of the BIOS Data Area equipment word at
|
||||
* 40:10.
|
||||
*/
|
||||
static uint8_t num_drives;
|
||||
static uint16_t equipment_word;
|
||||
|
||||
/**
|
||||
* Number of BIOS floppy disk drives
|
||||
*
|
||||
* This is derived from the equipment word. It is held in .text16 to
|
||||
* allow for easy access by the INT 13,08 wrapper.
|
||||
*/
|
||||
static uint8_t __text16 ( num_fdds );
|
||||
#define num_fdds __use_text16 ( num_fdds )
|
||||
|
||||
/**
|
||||
* Number of BIOS hard disk drives
|
||||
*
|
||||
* This is a cached copy of the BIOS Data Area number of hard disk
|
||||
* drives at 40:75. It is held in .text16 to allow for easy access by
|
||||
* the INT 13,08 wrapper.
|
||||
*/
|
||||
static uint8_t __text16 ( num_drives );
|
||||
#define num_drives __use_text16 ( num_drives )
|
||||
|
||||
/**
|
||||
* Calculate INT 13 drive sector size
|
||||
@@ -160,7 +187,7 @@ static uint8_t num_drives;
|
||||
* @v int13 Emulated drive
|
||||
* @ret blksize Sector size
|
||||
*/
|
||||
static inline unsigned int int13_blksize ( struct int13_drive *int13 ) {
|
||||
static inline size_t int13_blksize ( struct int13_drive *int13 ) {
|
||||
return ( int13->capacity.blksize << int13->blksize_shift );
|
||||
}
|
||||
|
||||
@@ -185,6 +212,16 @@ static inline uint32_t int13_capacity32 ( struct int13_drive *int13 ) {
|
||||
return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if INT 13 drive is a floppy disk drive
|
||||
*
|
||||
* @v int13 Emulated drive
|
||||
* @ret is_fdd Emulated drive is a floppy disk
|
||||
*/
|
||||
static inline int int13_is_fdd ( struct int13_drive *int13 ) {
|
||||
return ( ! ( int13->drive & 0x80 ) );
|
||||
}
|
||||
|
||||
/** An INT 13 command */
|
||||
struct int13_command {
|
||||
/** Status */
|
||||
@@ -499,33 +536,33 @@ static int int13_parse_iso9660 ( struct int13_drive *int13, void *scratch ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess INT 13 drive geometry
|
||||
* Guess INT 13 hard disk drive geometry
|
||||
*
|
||||
* @v int13 Emulated drive
|
||||
* @v scratch Scratch area for single-sector reads
|
||||
* @ret heads Guessed number of heads
|
||||
* @ret sectors Guessed number of sectors per track
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Guesses the drive geometry by inspecting the partition table.
|
||||
*/
|
||||
static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
|
||||
static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch,
|
||||
unsigned int *heads,
|
||||
unsigned int *sectors ) {
|
||||
struct master_boot_record *mbr = scratch;
|
||||
struct partition_table_entry *partition;
|
||||
unsigned int guessed_heads = 255;
|
||||
unsigned int guessed_sectors_per_track = 63;
|
||||
unsigned int blocks;
|
||||
unsigned int blocks_per_cyl;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Don't even try when the blksize is invalid for C/H/S access */
|
||||
if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
|
||||
return 0;
|
||||
/* Default guess is xx/255/63 */
|
||||
*heads = 255;
|
||||
*sectors = 63;
|
||||
|
||||
/* Read partition table */
|
||||
if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( mbr ),
|
||||
block_read ) ) != 0 ) {
|
||||
DBGC ( int13, "INT13 drive %02x could not read partition "
|
||||
"table to guess geometry: %s\n",
|
||||
DBGC ( int13, "INT13 drive %02x could not read "
|
||||
"partition table to guess geometry: %s\n",
|
||||
int13->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
@@ -534,25 +571,126 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
|
||||
DBGC ( int13, "INT13 drive %02x has signature %08x\n",
|
||||
int13->drive, mbr->signature );
|
||||
|
||||
/* Scan through partition table and modify guesses for heads
|
||||
* and sectors_per_track if we find any used partitions.
|
||||
/* Scan through partition table and modify guesses for
|
||||
* heads and sectors_per_track if we find any used
|
||||
* partitions.
|
||||
*/
|
||||
for ( i = 0 ; i < 4 ; i++ ) {
|
||||
partition = &mbr->partitions[i];
|
||||
if ( ! partition->type )
|
||||
continue;
|
||||
guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
|
||||
guessed_sectors_per_track = PART_SECTOR ( partition->chs_end );
|
||||
*heads = ( PART_HEAD ( partition->chs_end ) + 1 );
|
||||
*sectors = PART_SECTOR ( partition->chs_end );
|
||||
DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
|
||||
"on partition %d\n", int13->drive, guessed_heads,
|
||||
guessed_sectors_per_track, ( i + 1 ) );
|
||||
"on partition %d\n",
|
||||
int13->drive, *heads, *sectors, ( i + 1 ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Recognised floppy disk geometries */
|
||||
static const struct int13_fdd_geometry int13_fdd_geometries[] = {
|
||||
INT13_FDD_GEOMETRY ( 40, 1, 8 ),
|
||||
INT13_FDD_GEOMETRY ( 40, 1, 9 ),
|
||||
INT13_FDD_GEOMETRY ( 40, 2, 8 ),
|
||||
INT13_FDD_GEOMETRY ( 40, 1, 9 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 8 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 9 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 15 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 18 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 20 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 21 ),
|
||||
INT13_FDD_GEOMETRY ( 82, 2, 21 ),
|
||||
INT13_FDD_GEOMETRY ( 83, 2, 21 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 22 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 23 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 24 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 36 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 39 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 40 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 44 ),
|
||||
INT13_FDD_GEOMETRY ( 80, 2, 48 ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Guess INT 13 floppy disk drive geometry
|
||||
*
|
||||
* @v int13 Emulated drive
|
||||
* @ret heads Guessed number of heads
|
||||
* @ret sectors Guessed number of sectors per track
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Guesses the drive geometry by inspecting the disk size.
|
||||
*/
|
||||
static int int13_guess_geometry_fdd ( struct int13_drive *int13,
|
||||
unsigned int *heads,
|
||||
unsigned int *sectors ) {
|
||||
unsigned int blocks = int13_blksize ( int13 );
|
||||
const struct int13_fdd_geometry *geometry;
|
||||
unsigned int cylinders;
|
||||
unsigned int i;
|
||||
|
||||
/* Look for a match against a known geometry */
|
||||
for ( i = 0 ; i < ( sizeof ( int13_fdd_geometries ) /
|
||||
sizeof ( int13_fdd_geometries[0] ) ) ; i++ ) {
|
||||
geometry = &int13_fdd_geometries[i];
|
||||
cylinders = INT13_FDD_CYLINDERS ( geometry );
|
||||
*heads = INT13_FDD_HEADS ( geometry );
|
||||
*sectors = INT13_FDD_SECTORS ( geometry );
|
||||
if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
|
||||
DBGC ( int13, "INT13 drive %02x guessing C/H/S "
|
||||
"%d/%d/%d based on size %dK\n", int13->drive,
|
||||
cylinders, *heads, *sectors, ( blocks / 2 ) );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, assume a partial disk image in the most common
|
||||
* format (1440K, 80/2/18).
|
||||
*/
|
||||
*heads = 2;
|
||||
*sectors = 18;
|
||||
DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
|
||||
"%dK\n", int13->drive, *heads, *sectors, ( blocks / 2 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess INT 13 drive geometry
|
||||
*
|
||||
* @v int13 Emulated drive
|
||||
* @v scratch Scratch area for single-sector reads
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
|
||||
unsigned int guessed_heads;
|
||||
unsigned int guessed_sectors;
|
||||
unsigned int blocks;
|
||||
unsigned int blocks_per_cyl;
|
||||
int rc;
|
||||
|
||||
/* Don't even try when the blksize is invalid for C/H/S access */
|
||||
if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
|
||||
return 0;
|
||||
|
||||
/* Guess geometry according to drive type */
|
||||
if ( int13_is_fdd ( int13 ) ) {
|
||||
if ( ( rc = int13_guess_geometry_fdd ( int13, &guessed_heads,
|
||||
&guessed_sectors )) != 0)
|
||||
return rc;
|
||||
} else {
|
||||
if ( ( rc = int13_guess_geometry_hdd ( int13, scratch,
|
||||
&guessed_heads,
|
||||
&guessed_sectors )) != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Apply guesses if no geometry already specified */
|
||||
if ( ! int13->heads )
|
||||
int13->heads = guessed_heads;
|
||||
if ( ! int13->sectors_per_track )
|
||||
int13->sectors_per_track = guessed_sectors_per_track;
|
||||
int13->sectors_per_track = guessed_sectors;
|
||||
if ( ! int13->cylinders ) {
|
||||
/* Avoid attempting a 64-bit divide on a 32-bit system */
|
||||
blocks = int13_capacity32 ( int13 );
|
||||
@@ -569,19 +707,40 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
|
||||
/**
|
||||
* Update BIOS drive count
|
||||
*/
|
||||
static void int13_set_num_drives ( void ) {
|
||||
static void int13_sync_num_drives ( void ) {
|
||||
struct int13_drive *int13;
|
||||
uint8_t *counter;
|
||||
uint8_t max_drive;
|
||||
uint8_t required;
|
||||
|
||||
/* Get current drive count */
|
||||
/* Get current drive counts */
|
||||
get_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
|
||||
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
|
||||
num_fdds = ( ( equipment_word & 0x0001 ) ?
|
||||
( ( ( equipment_word >> 6 ) & 0x3 ) + 1 ) : 0 );
|
||||
|
||||
/* Ensure count is large enough to cover all of our emulated drives */
|
||||
list_for_each_entry ( int13, &int13s, list ) {
|
||||
if ( num_drives <= ( int13->drive & 0x7f ) )
|
||||
num_drives = ( ( int13->drive & 0x7f ) + 1 );
|
||||
counter = ( int13_is_fdd ( int13 ) ? &num_fdds : &num_drives );
|
||||
max_drive = int13->drive;
|
||||
if ( max_drive < int13->natural_drive )
|
||||
max_drive = int13->natural_drive;
|
||||
required = ( ( max_drive & 0x7f ) + 1 );
|
||||
if ( *counter < required ) {
|
||||
*counter = required;
|
||||
DBGC ( int13, "INT13 drive %02x added to drive count: "
|
||||
"%d HDDs, %d FDDs\n",
|
||||
int13->drive, num_drives, num_fdds );
|
||||
}
|
||||
}
|
||||
|
||||
/* Update current drive count */
|
||||
equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 );
|
||||
if ( num_fdds ) {
|
||||
equipment_word |= ( 0x0001 |
|
||||
( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) );
|
||||
}
|
||||
put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
|
||||
put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
|
||||
}
|
||||
|
||||
@@ -589,13 +748,14 @@ static void int13_set_num_drives ( void ) {
|
||||
* Check number of drives
|
||||
*/
|
||||
static void int13_check_num_drives ( void ) {
|
||||
uint16_t check_equipment_word;
|
||||
uint8_t check_num_drives;
|
||||
|
||||
get_real ( check_equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
|
||||
get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
|
||||
if ( check_num_drives != num_drives ) {
|
||||
int13_set_num_drives();
|
||||
DBG ( "INT13 fixing up number of drives from %d to %d\n",
|
||||
check_num_drives, num_drives );
|
||||
if ( ( check_equipment_word != equipment_word ) ||
|
||||
( check_num_drives != num_drives ) ) {
|
||||
int13_sync_num_drives();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,14 +829,19 @@ static int int13_rw_sectors ( struct int13_drive *int13,
|
||||
int13->drive, int13_blksize ( int13 ) );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/* Calculate parameters */
|
||||
cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
|
||||
assert ( cylinder < int13->cylinders );
|
||||
head = ix86->regs.dh;
|
||||
assert ( head < int13->heads );
|
||||
sector = ( ix86->regs.cl & 0x3f );
|
||||
assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) );
|
||||
if ( ( cylinder >= int13->cylinders ) ||
|
||||
( head >= int13->heads ) ||
|
||||
( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
|
||||
DBGC ( int13, "C/H/S %d/%d/%d out of range for geometry "
|
||||
"%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
|
||||
int13->heads, int13->sectors_per_track );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
lba = ( ( ( ( cylinder * int13->heads ) + head )
|
||||
* int13->sectors_per_track ) + sector - 1 );
|
||||
count = ix86->regs.al;
|
||||
@@ -761,10 +926,19 @@ static int int13_get_parameters ( struct int13_drive *int13,
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
|
||||
/* Common parameters */
|
||||
ix86->regs.ch = ( max_cylinder & 0xff );
|
||||
ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
|
||||
ix86->regs.dh = max_head;
|
||||
get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES );
|
||||
ix86->regs.dl = ( int13_is_fdd ( int13 ) ? num_fdds : num_drives );
|
||||
|
||||
/* Floppy-specific parameters */
|
||||
if ( int13_is_fdd ( int13 ) ) {
|
||||
ix86->regs.bl = INT13_FDD_TYPE_1M44;
|
||||
ix86->segs.es = rm_ds;
|
||||
ix86->regs.di = __from_data16 ( &int13_fdd_params );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -781,10 +955,15 @@ static int int13_get_disk_type ( struct int13_drive *int13,
|
||||
uint32_t blocks;
|
||||
|
||||
DBGC2 ( int13, "Get disk type\n" );
|
||||
blocks = int13_capacity32 ( int13 );
|
||||
ix86->regs.cx = ( blocks >> 16 );
|
||||
ix86->regs.dx = ( blocks & 0xffff );
|
||||
return INT13_DISK_TYPE_HDD;
|
||||
|
||||
if ( int13_is_fdd ( int13 ) ) {
|
||||
return INT13_DISK_TYPE_FDD;
|
||||
} else {
|
||||
blocks = int13_capacity32 ( int13 );
|
||||
ix86->regs.cx = ( blocks >> 16 );
|
||||
ix86->regs.dx = ( blocks & 0xffff );
|
||||
return INT13_DISK_TYPE_HDD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -833,6 +1012,13 @@ static int int13_extended_rw ( struct int13_drive *int13,
|
||||
userptr_t buffer;
|
||||
int rc;
|
||||
|
||||
/* Extended reads are not allowed on floppy drives.
|
||||
* ELTORITO.SYS seems to assume that we are really a CD-ROM if
|
||||
* we support extended reads for a floppy drive.
|
||||
*/
|
||||
if ( int13_is_fdd ( int13 ) )
|
||||
return -INT13_STATUS_INVALID;
|
||||
|
||||
/* Get buffer size */
|
||||
get_real ( bufsize, ix86->segs.ds,
|
||||
( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
|
||||
@@ -1300,26 +1486,28 @@ static void int13_hook_vector ( void ) {
|
||||
"popw 6(%%bp)\n\t"
|
||||
/* Fix up %dl:
|
||||
*
|
||||
* INT 13,15 : do nothing
|
||||
* INT 13,15 : do nothing if hard disk
|
||||
* INT 13,08 : load with number of drives
|
||||
* all others: restore original value
|
||||
*/
|
||||
"cmpb $0x15, -1(%%bp)\n\t"
|
||||
"je 2f\n\t"
|
||||
"jne 2f\n\t"
|
||||
"testb $0x80, -4(%%bp)\n\t"
|
||||
"jnz 3f\n\t"
|
||||
"\n2:\n\t"
|
||||
"movb -4(%%bp), %%dl\n\t"
|
||||
"cmpb $0x08, -1(%%bp)\n\t"
|
||||
"jne 2f\n\t"
|
||||
"pushw %%ds\n\t"
|
||||
"pushw %1\n\t"
|
||||
"popw %%ds\n\t"
|
||||
"movb %c2, %%dl\n\t"
|
||||
"popw %%ds\n\t"
|
||||
"jne 3f\n\t"
|
||||
"testb $0x80, %%dl\n\t"
|
||||
"movb %%cs:num_drives, %%dl\n\t"
|
||||
"jnz 3f\n\t"
|
||||
"movb %%cs:num_fdds, %%dl\n\t"
|
||||
/* Return */
|
||||
"\n2:\n\t"
|
||||
"\n3:\n\t"
|
||||
"movw %%bp, %%sp\n\t"
|
||||
"popw %%bp\n\t"
|
||||
"iret\n\t" )
|
||||
: : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) );
|
||||
: : "i" ( int13 ) );
|
||||
|
||||
hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
|
||||
&int13_vector );
|
||||
@@ -1404,14 +1592,13 @@ static void int13_free ( struct refcnt *refcnt ) {
|
||||
*/
|
||||
static int int13_hook ( struct uri *uri, unsigned int drive ) {
|
||||
struct int13_drive *int13;
|
||||
uint8_t num_drives;
|
||||
unsigned int natural_drive;
|
||||
void *scratch;
|
||||
int rc;
|
||||
|
||||
/* Calculate natural drive number */
|
||||
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
|
||||
natural_drive = ( num_drives | 0x80 );
|
||||
int13_sync_num_drives();
|
||||
natural_drive = ( ( drive & 0x80 ) ? ( num_drives | 0x80 ) : num_fdds );
|
||||
|
||||
/* Check that drive number is not in use */
|
||||
list_for_each_entry ( int13, &int13s, list ) {
|
||||
@@ -1468,7 +1655,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
|
||||
list_add ( &int13->list, &int13s );
|
||||
|
||||
/* Update BIOS drive count */
|
||||
int13_set_num_drives();
|
||||
int13_sync_num_drives();
|
||||
|
||||
free ( scratch );
|
||||
return 0;
|
||||
|
||||
@@ -52,6 +52,9 @@ static userptr_t top = UNULL;
|
||||
/** Bottom of heap (current lowest allocated block) */
|
||||
static userptr_t bottom = UNULL;
|
||||
|
||||
/** Remaining space on heap */
|
||||
static size_t heap_size;
|
||||
|
||||
/**
|
||||
* Initialise external heap
|
||||
*
|
||||
@@ -59,12 +62,12 @@ static userptr_t bottom = UNULL;
|
||||
*/
|
||||
static int init_eheap ( void ) {
|
||||
struct memory_map memmap;
|
||||
unsigned long heap_size = 0;
|
||||
unsigned int i;
|
||||
|
||||
DBG ( "Allocating external heap\n" );
|
||||
|
||||
get_memmap ( &memmap );
|
||||
heap_size = 0;
|
||||
for ( i = 0 ; i < memmap.count ; i++ ) {
|
||||
struct memory_region *region = &memmap.regions[i];
|
||||
unsigned long r_start, r_end;
|
||||
@@ -99,8 +102,8 @@ static int init_eheap ( void ) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DBG ( "External heap grows downwards from %lx\n",
|
||||
user_to_phys ( top, 0 ) );
|
||||
DBG ( "External heap grows downwards from %lx (size %zx)\n",
|
||||
user_to_phys ( top, 0 ), heap_size );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -110,6 +113,7 @@ static int init_eheap ( void ) {
|
||||
*/
|
||||
static void ecollect_free ( void ) {
|
||||
struct external_memory extmem;
|
||||
size_t len;
|
||||
|
||||
/* Walk the free list and collect empty blocks */
|
||||
while ( bottom != top ) {
|
||||
@@ -119,8 +123,9 @@ static void ecollect_free ( void ) {
|
||||
break;
|
||||
DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
|
||||
user_to_phys ( bottom, extmem.size ) );
|
||||
bottom = userptr_add ( bottom,
|
||||
( extmem.size + sizeof ( extmem ) ) );
|
||||
len = ( extmem.size + sizeof ( extmem ) );
|
||||
bottom = userptr_add ( bottom, len );
|
||||
heap_size += len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +158,12 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
|
||||
sizeof ( extmem ) );
|
||||
} else {
|
||||
/* Create a zero-length block */
|
||||
if ( heap_size < sizeof ( extmem ) ) {
|
||||
DBG ( "EXTMEM out of space\n" );
|
||||
return UNULL;
|
||||
}
|
||||
ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
|
||||
heap_size -= sizeof ( extmem );
|
||||
DBG ( "EXTMEM allocating [%lx,%lx)\n",
|
||||
user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
|
||||
extmem.size = 0;
|
||||
@@ -163,6 +173,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
|
||||
/* Expand/shrink block if possible */
|
||||
if ( ptr == bottom ) {
|
||||
/* Update block */
|
||||
if ( new_size > ( heap_size - extmem.size ) ) {
|
||||
DBG ( "EXTMEM out of space\n" );
|
||||
return UNULL;
|
||||
}
|
||||
new = userptr_add ( ptr, - ( new_size - extmem.size ) );
|
||||
align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
|
||||
new_size += align;
|
||||
@@ -174,8 +188,9 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
|
||||
user_to_phys ( new, new_size ));
|
||||
memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
|
||||
extmem.size : new_size ) );
|
||||
extmem.size = new_size;
|
||||
bottom = new;
|
||||
heap_size -= ( new_size - extmem.size );
|
||||
extmem.size = new_size;
|
||||
} else {
|
||||
/* Cannot expand; can only pretend to shrink */
|
||||
if ( new_size > extmem.size ) {
|
||||
@@ -193,7 +208,8 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
|
||||
|
||||
/* Collect any free blocks and update hidden memory region */
|
||||
ecollect_free();
|
||||
hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
|
||||
hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
|
||||
0 : -sizeof ( extmem ) ) ),
|
||||
user_to_phys ( top, 0 ) );
|
||||
|
||||
return ( new_size ? new : UNOWHERE );
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RTC-based entropy source
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <biosint.h>
|
||||
#include <pic8259.h>
|
||||
#include <rtc.h>
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
/** RTC "interrupt triggered" flag */
|
||||
static uint8_t __text16 ( rtc_flag );
|
||||
#define rtc_flag __use_text16 ( rtc_flag )
|
||||
|
||||
/** RTC interrupt handler */
|
||||
extern void rtc_isr ( void );
|
||||
|
||||
/** Previous RTC interrupt handler */
|
||||
static struct segoff rtc_old_handler;
|
||||
|
||||
/**
|
||||
* Hook RTC interrupt handler
|
||||
*
|
||||
*/
|
||||
static void rtc_hook_isr ( void ) {
|
||||
|
||||
/* RTC interrupt handler */
|
||||
__asm__ __volatile__ (
|
||||
TEXT16_CODE ( "\nrtc_isr:\n\t"
|
||||
/* Preserve registers */
|
||||
"pushw %%ax\n\t"
|
||||
/* Set "interrupt triggered" flag */
|
||||
"cs movb $0x01, %c0\n\t"
|
||||
/* Read RTC status register C to
|
||||
* acknowledge interrupt
|
||||
*/
|
||||
"movb %3, %%al\n\t"
|
||||
"outb %%al, %1\n\t"
|
||||
"inb %2\n\t"
|
||||
/* Send EOI */
|
||||
"movb $0x20, %%al\n\t"
|
||||
"outb %%al, $0xa0\n\t"
|
||||
"outb %%al, $0x20\n\t"
|
||||
/* Restore registers and return */
|
||||
"popw %%ax\n\t"
|
||||
"iret\n\t" )
|
||||
:
|
||||
: "p" ( __from_text16 ( &rtc_flag ) ),
|
||||
"i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
|
||||
"i" ( RTC_STATUS_C ) );
|
||||
|
||||
hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
|
||||
&rtc_old_handler );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unhook RTC interrupt handler
|
||||
*
|
||||
*/
|
||||
static void rtc_unhook_isr ( void ) {
|
||||
int rc;
|
||||
|
||||
rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
|
||||
&rtc_old_handler );
|
||||
assert ( rc == 0 ); /* Should always be able to unhook */
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable RTC interrupts
|
||||
*
|
||||
*/
|
||||
static void rtc_enable_int ( void ) {
|
||||
uint8_t status_b;
|
||||
|
||||
/* Set Periodic Interrupt Enable bit in status register B */
|
||||
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
|
||||
status_b = inb ( CMOS_DATA );
|
||||
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
|
||||
outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
|
||||
|
||||
/* Re-enable NMI and reset to default address */
|
||||
outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
|
||||
inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable RTC interrupts
|
||||
*
|
||||
*/
|
||||
static void rtc_disable_int ( void ) {
|
||||
uint8_t status_b;
|
||||
|
||||
/* Clear Periodic Interrupt Enable bit in status register B */
|
||||
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
|
||||
status_b = inb ( CMOS_DATA );
|
||||
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
|
||||
outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
|
||||
|
||||
/* Re-enable NMI and reset to default address */
|
||||
outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
|
||||
inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable entropy gathering
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rtc_entropy_enable ( void ) {
|
||||
|
||||
rtc_hook_isr();
|
||||
enable_irq ( RTC_IRQ );
|
||||
rtc_enable_int();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable entropy gathering
|
||||
*
|
||||
*/
|
||||
static void rtc_entropy_disable ( void ) {
|
||||
|
||||
rtc_disable_int();
|
||||
disable_irq ( RTC_IRQ );
|
||||
rtc_unhook_isr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure a single RTC tick
|
||||
*
|
||||
* @ret delta Length of RTC tick (in TSC units)
|
||||
*/
|
||||
uint8_t rtc_sample ( void ) {
|
||||
uint32_t before;
|
||||
uint32_t after;
|
||||
uint32_t temp;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
REAL_CODE ( /* Enable interrupts */
|
||||
"sti\n\t"
|
||||
/* Wait for RTC interrupt */
|
||||
"cs movb %b2, %c4\n\t"
|
||||
"\n1:\n\t"
|
||||
"cs xchgb %b2, %c4\n\t" /* Serialize */
|
||||
"testb %b2, %b2\n\t"
|
||||
"jz 1b\n\t"
|
||||
/* Read "before" TSC */
|
||||
"rdtsc\n\t"
|
||||
/* Store "before" TSC on stack */
|
||||
"pushl %0\n\t"
|
||||
/* Wait for another RTC interrupt */
|
||||
"xorb %b2, %b2\n\t"
|
||||
"cs movb %b2, %c4\n\t"
|
||||
"\n1:\n\t"
|
||||
"cs xchgb %b2, %c4\n\t" /* Serialize */
|
||||
"testb %b2, %b2\n\t"
|
||||
"jz 1b\n\t"
|
||||
/* Read "after" TSC */
|
||||
"rdtsc\n\t"
|
||||
/* Retrieve "before" TSC on stack */
|
||||
"popl %1\n\t"
|
||||
/* Disable interrupts */
|
||||
"cli\n\t"
|
||||
)
|
||||
: "=a" ( after ), "=d" ( before ), "=q" ( temp )
|
||||
: "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
|
||||
|
||||
return ( after - before );
|
||||
}
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
|
||||
PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
|
||||
PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RTC-based time source
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <rtc.h>
|
||||
#include <ipxe/time.h>
|
||||
|
||||
/**
|
||||
* Read RTC register
|
||||
*
|
||||
* @v address Register address
|
||||
* @ret data Data
|
||||
*/
|
||||
static unsigned int rtc_readb ( int address ) {
|
||||
outb ( address, CMOS_ADDRESS );
|
||||
return inb ( CMOS_DATA );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if RTC update is in progress
|
||||
*
|
||||
* @ret is_busy RTC update is in progress
|
||||
*/
|
||||
static int rtc_is_busy ( void ) {
|
||||
return ( rtc_readb ( RTC_STATUS_A ) & RTC_STATUS_A_UPDATE_IN_PROGRESS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read RTC BCD register
|
||||
*
|
||||
* @v address Register address
|
||||
* @ret value Value
|
||||
*/
|
||||
static unsigned int rtc_readb_bcd ( int address ) {
|
||||
unsigned int bcd;
|
||||
|
||||
bcd = rtc_readb ( address );
|
||||
return ( bcd - ( 6 * ( bcd >> 4 ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read RTC time
|
||||
*
|
||||
* @ret time Time, in seconds
|
||||
*/
|
||||
static time_t rtc_read_time ( void ) {
|
||||
unsigned int status_b;
|
||||
int is_binary;
|
||||
int is_24hour;
|
||||
unsigned int ( * read_component ) ( int address );
|
||||
struct tm tm;
|
||||
int is_pm;
|
||||
unsigned int hour;
|
||||
time_t time;
|
||||
|
||||
/* Wait for any in-progress update to complete */
|
||||
while ( rtc_is_busy() ) {}
|
||||
|
||||
/* Determine RTC mode */
|
||||
status_b = rtc_readb ( RTC_STATUS_B );
|
||||
is_binary = ( status_b & RTC_STATUS_B_BINARY );
|
||||
is_24hour = ( status_b & RTC_STATUS_B_24_HOUR );
|
||||
read_component = ( is_binary ? rtc_readb : rtc_readb_bcd );
|
||||
|
||||
/* Read time values */
|
||||
tm.tm_sec = read_component ( RTC_SEC );
|
||||
tm.tm_min = read_component ( RTC_MIN );
|
||||
hour = read_component ( RTC_HOUR );
|
||||
if ( ! is_24hour ) {
|
||||
is_pm = ( hour >= 80 );
|
||||
hour = ( ( ( ( hour & 0x7f ) % 80 ) % 12 ) +
|
||||
( is_pm ? 12 : 0 ) );
|
||||
}
|
||||
tm.tm_hour = hour;
|
||||
tm.tm_mday = read_component ( RTC_MDAY );
|
||||
tm.tm_mon = ( read_component ( RTC_MON ) - 1 );
|
||||
tm.tm_year = ( read_component ( RTC_YEAR ) +
|
||||
100 /* Assume we are in the 21st century, since
|
||||
* this code was written in 2012 */ );
|
||||
|
||||
DBGC ( RTC_STATUS_A, "RTCTIME is %04d-%02d-%02d %02d:%02d:%02d "
|
||||
"(%s,%d-hour)\n", ( tm.tm_year + 1900 ), ( tm.tm_mon + 1 ),
|
||||
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
( is_binary ? "binary" : "BCD" ), ( is_24hour ? 24 : 12 ) );
|
||||
|
||||
/* Convert to seconds since the Epoch */
|
||||
time = mktime ( &tm );
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current time in seconds
|
||||
*
|
||||
* @ret time Time, in seconds
|
||||
*/
|
||||
static time_t rtc_now ( void ) {
|
||||
time_t time = 0;
|
||||
time_t last_time;
|
||||
|
||||
/* Read time until we get two matching values in a row, in
|
||||
* case we end up reading a corrupted value in the middle of
|
||||
* an update.
|
||||
*/
|
||||
do {
|
||||
last_time = time;
|
||||
time = rtc_read_time();
|
||||
} while ( time != last_time );
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
PROVIDE_TIME ( rtc, time_now, rtc_now );
|
||||
@@ -166,6 +166,8 @@ void comboot_force_text_mode ( void ) {
|
||||
* Fetch kernel and optional initrd
|
||||
*/
|
||||
static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
|
||||
struct image *kernel;
|
||||
struct image *initrd;
|
||||
char *initrd_file;
|
||||
int rc;
|
||||
|
||||
@@ -184,8 +186,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
|
||||
DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file );
|
||||
|
||||
/* Fetch initrd */
|
||||
if ( ( rc = imgdownload_string ( initrd_file, NULL, NULL,
|
||||
NULL ) ) != 0 ) {
|
||||
if ( ( rc = imgdownload_string ( initrd_file, &initrd ) ) != 0){
|
||||
DBG ( "COMBOOT: could not fetch initrd: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
@@ -198,14 +199,20 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
|
||||
|
||||
DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file );
|
||||
|
||||
/* Allocate and fetch kernel */
|
||||
if ( ( rc = imgdownload_string ( kernel_file, NULL, cmdline,
|
||||
image_replace ) ) != 0 ) {
|
||||
/* Fetch kernel */
|
||||
if ( ( rc = imgdownload_string ( kernel_file, &kernel ) ) != 0 ) {
|
||||
DBG ( "COMBOOT: could not fetch kernel: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Replace comboot image with kernel */
|
||||
if ( ( rc = image_replace ( kernel ) ) != 0 ) {
|
||||
DBG ( "COMBOOT: could not replace with kernel: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VMware GuestInfo settings
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/guestrpc.h>
|
||||
|
||||
/** GuestInfo GuestRPC channel */
|
||||
static int guestinfo_channel;
|
||||
|
||||
/**
|
||||
* Fetch value of typed GuestInfo setting
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to fetch
|
||||
* @v type Setting type to attempt (or NULL for default)
|
||||
* @v data Buffer to fill with setting data
|
||||
* @v len Length of buffer
|
||||
* @ret found Setting found in GuestInfo
|
||||
* @ret len Length of setting data, or negative error
|
||||
*/
|
||||
static int guestinfo_fetch_type ( struct settings *settings,
|
||||
struct setting *setting,
|
||||
struct setting_type *type,
|
||||
void *data, size_t len, int *found ) {
|
||||
const char *parent_name = settings->parent->name;
|
||||
char command[ 24 /* "info-get guestinfo.ipxe." */ +
|
||||
strlen ( parent_name ) + 1 /* "." */ +
|
||||
strlen ( setting->name ) + 1 /* "." */ +
|
||||
( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
|
||||
struct setting *named_setting;
|
||||
char *info;
|
||||
int info_len;
|
||||
int check_len;
|
||||
int ret;
|
||||
|
||||
/* Construct info-get command */
|
||||
snprintf ( command, sizeof ( command ),
|
||||
"info-get guestinfo.ipxe.%s%s%s%s%s",
|
||||
parent_name, ( parent_name[0] ? "." : "" ), setting->name,
|
||||
( type ? "." : "" ), ( type ? type->name : "" ) );
|
||||
|
||||
/* Check for existence and obtain length of GuestInfo value */
|
||||
info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
|
||||
if ( info_len < 0 ) {
|
||||
ret = info_len;
|
||||
goto err_get_info_len;
|
||||
}
|
||||
|
||||
/* Mark as found */
|
||||
*found = 1;
|
||||
|
||||
/* Determine default type if necessary */
|
||||
if ( ! type ) {
|
||||
named_setting = find_setting ( setting->name );
|
||||
type = ( named_setting ?
|
||||
named_setting->type : &setting_type_string );
|
||||
}
|
||||
assert ( type != NULL );
|
||||
|
||||
/* Allocate temporary block to hold GuestInfo value */
|
||||
info = zalloc ( info_len + 1 /* NUL */ );
|
||||
if ( ! info ) {
|
||||
DBGC ( settings, "GuestInfo %p could not allocate %zd bytes\n",
|
||||
settings, info_len );
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
info[info_len] = '\0';
|
||||
|
||||
/* Fetch GuestInfo value */
|
||||
check_len = guestrpc_command ( guestinfo_channel, command,
|
||||
info, info_len );
|
||||
if ( check_len < 0 ) {
|
||||
ret = check_len;
|
||||
goto err_get_info;
|
||||
}
|
||||
if ( check_len != info_len ) {
|
||||
DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
|
||||
"got %d)\n", settings, info_len, check_len );
|
||||
ret = -EIO;
|
||||
goto err_get_info;
|
||||
}
|
||||
DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
|
||||
settings, &command[9] /* Skip "info-get " */, info );
|
||||
|
||||
/* Parse GuestInfo value according to type */
|
||||
ret = type->parse ( info, data, len );
|
||||
if ( ret < 0 ) {
|
||||
DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
|
||||
"%s\n", settings, info, type->name, strerror ( ret ) );
|
||||
goto err_parse;
|
||||
}
|
||||
|
||||
err_parse:
|
||||
err_get_info:
|
||||
free ( info );
|
||||
err_alloc:
|
||||
err_get_info_len:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch value of GuestInfo setting
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to fetch
|
||||
* @v data Buffer to fill with setting data
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of setting data, or negative error
|
||||
*/
|
||||
static int guestinfo_fetch ( struct settings *settings,
|
||||
struct setting *setting,
|
||||
void *data, size_t len ) {
|
||||
struct setting_type *type;
|
||||
int found = 0;
|
||||
int ret;
|
||||
|
||||
/* Try default type first */
|
||||
ret = guestinfo_fetch_type ( settings, setting, NULL,
|
||||
data, len, &found );
|
||||
if ( found )
|
||||
return ret;
|
||||
|
||||
/* Otherwise, try all possible types */
|
||||
for_each_table_entry ( type, SETTING_TYPES ) {
|
||||
ret = guestinfo_fetch_type ( settings, setting, type,
|
||||
data, len, &found );
|
||||
if ( found )
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/** GuestInfo settings operations */
|
||||
static struct settings_operations guestinfo_settings_operations = {
|
||||
.fetch = guestinfo_fetch,
|
||||
};
|
||||
|
||||
/** GuestInfo settings */
|
||||
static struct settings guestinfo_settings = {
|
||||
.refcnt = NULL,
|
||||
.siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
|
||||
.children = LIST_HEAD_INIT ( guestinfo_settings.children ),
|
||||
.op = &guestinfo_settings_operations,
|
||||
};
|
||||
|
||||
/** Initialise GuestInfo settings */
|
||||
static void guestinfo_init ( void ) {
|
||||
int rc;
|
||||
|
||||
/* Open GuestRPC channel */
|
||||
guestinfo_channel = guestrpc_open();
|
||||
if ( guestinfo_channel < 0 ) {
|
||||
rc = guestinfo_channel;
|
||||
DBG ( "GuestInfo could not open channel: %s\n",
|
||||
strerror ( rc ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register root GuestInfo settings */
|
||||
if ( ( rc = register_settings ( &guestinfo_settings, NULL,
|
||||
"vmware" ) ) != 0 ) {
|
||||
DBG ( "GuestInfo could not register settings: %s\n",
|
||||
strerror ( rc ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** GuestInfo settings initialiser */
|
||||
struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = guestinfo_init,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create per-netdevice GuestInfo settings
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int guestinfo_net_probe ( struct net_device *netdev ) {
|
||||
struct settings *settings;
|
||||
int rc;
|
||||
|
||||
/* Do nothing unless we have a GuestInfo channel available */
|
||||
if ( guestinfo_channel < 0 )
|
||||
return 0;
|
||||
|
||||
/* Allocate and initialise settings block */
|
||||
settings = zalloc ( sizeof ( *settings ) );
|
||||
if ( ! settings ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
settings_init ( settings, &guestinfo_settings_operations, NULL, 0 );
|
||||
|
||||
/* Register settings */
|
||||
if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
|
||||
"vmware" ) ) != 0 ) {
|
||||
DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
|
||||
settings, netdev->name, strerror ( rc ) );
|
||||
goto err_register;
|
||||
}
|
||||
DBGC ( settings, "GuestInfo %p registered for %s\n",
|
||||
settings, netdev->name );
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
free ( settings );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle network device or link state change
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void guestinfo_net_notify ( struct net_device *netdev __unused ) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove per-netdevice GuestInfo settings
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void guestinfo_net_remove ( struct net_device *netdev ) {
|
||||
struct settings *parent = netdev_settings ( netdev );
|
||||
struct settings *settings;
|
||||
|
||||
list_for_each_entry ( settings, &parent->children, siblings ) {
|
||||
if ( settings->op == &guestinfo_settings_operations ) {
|
||||
DBGC ( settings, "GuestInfo %p unregistered for %s\n",
|
||||
settings, netdev->name );
|
||||
unregister_settings ( settings );
|
||||
free ( settings );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** GuestInfo per-netdevice driver */
|
||||
struct net_driver guestinfo_net_driver __net_driver = {
|
||||
.name = "GuestInfo",
|
||||
.probe = guestinfo_net_probe,
|
||||
.notify = guestinfo_net_notify,
|
||||
.remove = guestinfo_net_remove,
|
||||
};
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VMware GuestRPC mechanism
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/vmware.h>
|
||||
#include <ipxe/guestrpc.h>
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EPROTO_OPEN __einfo_error ( EINFO_EPROTO_OPEN )
|
||||
#define EINFO_EPROTO_OPEN \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x00, "GuestRPC open failed" )
|
||||
#define EPROTO_COMMAND_LEN __einfo_error ( EINFO_EPROTO_COMMAND_LEN )
|
||||
#define EINFO_EPROTO_COMMAND_LEN \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x01, "GuestRPC command length failed" )
|
||||
#define EPROTO_COMMAND_DATA __einfo_error ( EINFO_EPROTO_COMMAND_DATA )
|
||||
#define EINFO_EPROTO_COMMAND_DATA \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x02, "GuestRPC command data failed" )
|
||||
#define EPROTO_REPLY_LEN __einfo_error ( EINFO_EPROTO_REPLY_LEN )
|
||||
#define EINFO_EPROTO_REPLY_LEN \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x03, "GuestRPC reply length failed" )
|
||||
#define EPROTO_REPLY_DATA __einfo_error ( EINFO_EPROTO_REPLY_DATA )
|
||||
#define EINFO_EPROTO_REPLY_DATA \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x04, "GuestRPC reply data failed" )
|
||||
#define EPROTO_REPLY_FINISH __einfo_error ( EINFO_EPROTO_REPLY_FINISH )
|
||||
#define EINFO_EPROTO_REPLY_FINISH \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x05, "GuestRPC reply finish failed" )
|
||||
#define EPROTO_CLOSE __einfo_error ( EINFO_EPROTO_CLOSE )
|
||||
#define EINFO_EPROTO_CLOSE \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x06, "GuestRPC close failed" )
|
||||
|
||||
/**
|
||||
* Open GuestRPC channel
|
||||
*
|
||||
* @ret channel Channel number, or negative error
|
||||
*/
|
||||
int guestrpc_open ( void ) {
|
||||
uint16_t channel;
|
||||
uint32_t discard_b;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( 0, GUESTRPC_OPEN, GUESTRPC_MAGIC,
|
||||
&channel, &discard_b );
|
||||
if ( status != GUESTRPC_OPEN_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC open failed: status %08x\n",
|
||||
status );
|
||||
return -EPROTO_OPEN;
|
||||
}
|
||||
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel );
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send GuestRPC command length
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @v len Command length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int guestrpc_command_len ( int channel, size_t len ) {
|
||||
uint16_t discard_d;
|
||||
uint32_t discard_b;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len,
|
||||
&discard_d, &discard_b );
|
||||
if ( status != GUESTRPC_COMMAND_LEN_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
|
||||
"length %zd failed: status %08x\n",
|
||||
channel, len, status );
|
||||
return -EPROTO_COMMAND_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send GuestRPC command data
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @v data Command data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int guestrpc_command_data ( int channel, uint32_t data ) {
|
||||
uint16_t discard_d;
|
||||
uint32_t discard_b;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data,
|
||||
&discard_d, &discard_b );
|
||||
if ( status != GUESTRPC_COMMAND_DATA_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
|
||||
"data %08x failed: status %08x\n",
|
||||
channel, data, status );
|
||||
return -EPROTO_COMMAND_DATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive GuestRPC reply length
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @ret reply_id Reply ID
|
||||
* @ret len Reply length, or negative error
|
||||
*/
|
||||
static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) {
|
||||
uint32_t len;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
|
||||
reply_id, &len );
|
||||
if ( status != GUESTRPC_REPLY_LEN_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
|
||||
"length failed: status %08x\n", channel, status );
|
||||
return -EPROTO_REPLY_LEN;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive GuestRPC reply data
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @v reply_id Reply ID
|
||||
* @ret data Reply data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int guestrpc_reply_data ( int channel, uint16_t reply_id,
|
||||
uint32_t *data ) {
|
||||
uint16_t discard_d;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
|
||||
&discard_d, data );
|
||||
if ( status != GUESTRPC_REPLY_DATA_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
|
||||
"%d data failed: status %08x\n",
|
||||
channel, reply_id, status );
|
||||
return -EPROTO_REPLY_DATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish receiving GuestRPC reply
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @v reply_id Reply ID
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) {
|
||||
uint16_t discard_d;
|
||||
uint32_t discard_b;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id,
|
||||
&discard_d, &discard_b );
|
||||
if ( status != GUESTRPC_REPLY_FINISH_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d finish reply %d "
|
||||
"failed: status %08x\n", channel, reply_id, status );
|
||||
return -EPROTO_REPLY_FINISH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close GuestRPC channel
|
||||
*
|
||||
* @v channel Channel number
|
||||
*/
|
||||
void guestrpc_close ( int channel ) {
|
||||
uint16_t discard_d;
|
||||
uint32_t discard_b;
|
||||
uint32_t status;
|
||||
|
||||
/* Issue GuestRPC command */
|
||||
status = vmware_cmd_guestrpc ( channel, GUESTRPC_CLOSE, 0,
|
||||
&discard_d, &discard_b );
|
||||
if ( status != GUESTRPC_CLOSE_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d close failed: "
|
||||
"status %08x\n", channel, status );
|
||||
return;
|
||||
}
|
||||
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel );
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue GuestRPC command
|
||||
*
|
||||
* @v channel Channel number
|
||||
* @v command Command
|
||||
* @v reply Reply buffer
|
||||
* @v reply_len Length of reply buffer
|
||||
* @ret len Length of reply, or negative error
|
||||
*
|
||||
* The actual length of the reply will be returned even if the buffer
|
||||
* was too small.
|
||||
*/
|
||||
int guestrpc_command ( int channel, const char *command, char *reply,
|
||||
size_t reply_len ) {
|
||||
const uint8_t *command_bytes = ( ( const void * ) command );
|
||||
uint8_t *reply_bytes = ( ( void * ) reply );
|
||||
size_t command_len = strlen ( command );
|
||||
int orig_reply_len = reply_len;
|
||||
uint16_t status;
|
||||
uint8_t *status_bytes = ( ( void * ) &status );
|
||||
size_t status_len = sizeof ( status );
|
||||
uint32_t data;
|
||||
uint16_t reply_id;
|
||||
int len;
|
||||
int remaining;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n",
|
||||
channel );
|
||||
DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ( reply != NULL ) || ( reply_len == 0 ) );
|
||||
|
||||
/* Send command length */
|
||||
if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 )
|
||||
return rc;
|
||||
|
||||
/* Send command data */
|
||||
while ( command_len ) {
|
||||
data = 0;
|
||||
for ( i = sizeof ( data ) ; i ; i-- ) {
|
||||
if ( command_len ) {
|
||||
data = ( ( data & ~0xff ) |
|
||||
*(command_bytes++) );
|
||||
command_len--;
|
||||
}
|
||||
data = ( ( data << 24 ) | ( data >> 8 ) );
|
||||
}
|
||||
if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Receive reply length */
|
||||
if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) {
|
||||
rc = len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Receive reply */
|
||||
for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) {
|
||||
if ( ( rc = guestrpc_reply_data ( channel, reply_id,
|
||||
&data ) ) < 0 ) {
|
||||
return rc;
|
||||
}
|
||||
for ( i = sizeof ( data ) ; i ; i-- ) {
|
||||
if ( status_len ) {
|
||||
*(status_bytes++) = ( data & 0xff );
|
||||
status_len--;
|
||||
len--;
|
||||
} else if ( reply_len ) {
|
||||
*(reply_bytes++) = ( data & 0xff );
|
||||
reply_len--;
|
||||
}
|
||||
data = ( ( data << 24 ) | ( data >> 8 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish receiving RPC reply */
|
||||
if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 )
|
||||
return rc;
|
||||
|
||||
DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d received reply (id %d, "
|
||||
"length %d):\n", channel, reply_id, len );
|
||||
DBGC2_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
|
||||
DBGC2_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
|
||||
( ( len < orig_reply_len ) ? len : orig_reply_len ) );
|
||||
|
||||
/* Check reply status */
|
||||
if ( status != GUESTRPC_SUCCESS ) {
|
||||
DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d command failed "
|
||||
"(status %04x, reply id %d, reply length %d):\n",
|
||||
channel, status, reply_id, len );
|
||||
DBGC_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
|
||||
DBGC_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
|
||||
DBGC_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
|
||||
( ( len < orig_reply_len ) ? len : orig_reply_len ));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VMware logfile console
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ipxe/console.h>
|
||||
#include <ipxe/lineconsole.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/guestrpc.h>
|
||||
#include <config/console.h>
|
||||
|
||||
/** VMware logfile console buffer size */
|
||||
#define VMCONSOLE_BUFSIZE 128
|
||||
|
||||
/* Set default console usage if applicable */
|
||||
#if ! ( defined ( CONSOLE_VMWARE ) && CONSOLE_EXPLICIT ( CONSOLE_VMWARE ) )
|
||||
#undef CONSOLE_VMWARE
|
||||
#define CONSOLE_VMWARE ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
|
||||
#endif
|
||||
|
||||
/** VMware logfile console GuestRPC channel */
|
||||
static int vmconsole_channel;
|
||||
|
||||
/** VMware logfile console line buffer */
|
||||
static struct {
|
||||
char prefix[4];
|
||||
char message[VMCONSOLE_BUFSIZE];
|
||||
} vmconsole_buffer = {
|
||||
.prefix = "log ",
|
||||
};
|
||||
|
||||
/** VMware logfile console ANSI escape sequence handlers */
|
||||
static struct ansiesc_handler vmconsole_handlers[] = {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/** VMware logfile line console */
|
||||
static struct line_console vmconsole_line = {
|
||||
.buffer = vmconsole_buffer.message,
|
||||
.len = sizeof ( vmconsole_buffer.message ),
|
||||
.ctx = {
|
||||
.handlers = vmconsole_handlers,
|
||||
},
|
||||
};
|
||||
|
||||
/** VMware logfile console recursion marker */
|
||||
static int vmconsole_entered;
|
||||
|
||||
/**
|
||||
* Print a character to VMware logfile console
|
||||
*
|
||||
* @v character Character to be printed
|
||||
*/
|
||||
static void vmconsole_putchar ( int character ) {
|
||||
int rc;
|
||||
|
||||
/* Ignore if we are already mid-logging */
|
||||
if ( vmconsole_entered )
|
||||
return;
|
||||
|
||||
/* Fill line buffer */
|
||||
if ( line_putchar ( &vmconsole_line, character ) == 0 )
|
||||
return;
|
||||
|
||||
/* Guard against re-entry */
|
||||
vmconsole_entered = 1;
|
||||
|
||||
/* Send log message */
|
||||
if ( ( rc = guestrpc_command ( vmconsole_channel,
|
||||
vmconsole_buffer.prefix, NULL, 0 ) ) <0){
|
||||
DBG ( "VMware console could not send log message: %s\n",
|
||||
strerror ( rc ) );
|
||||
}
|
||||
|
||||
/* Clear re-entry flag */
|
||||
vmconsole_entered = 0;
|
||||
}
|
||||
|
||||
/** VMware logfile console driver */
|
||||
struct console_driver vmconsole __console_driver = {
|
||||
.putchar = vmconsole_putchar,
|
||||
.disabled = 1,
|
||||
.usage = CONSOLE_VMWARE,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise VMware logfile console
|
||||
*
|
||||
*/
|
||||
static void vmconsole_init ( void ) {
|
||||
int rc;
|
||||
|
||||
/* Attempt to open console */
|
||||
vmconsole_channel = guestrpc_open();
|
||||
if ( vmconsole_channel < 0 ) {
|
||||
rc = vmconsole_channel;
|
||||
DBG ( "VMware console could not be initialised: %s\n",
|
||||
strerror ( rc ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark console as available */
|
||||
vmconsole.disabled = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* VMware logfile console initialisation function
|
||||
*/
|
||||
struct init_fn vmconsole_init_fn __init_fn ( INIT_CONSOLE ) = {
|
||||
.initialise = vmconsole_init,
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* VMware backdoor mechanism
|
||||
*
|
||||
* Based on the unofficial documentation at
|
||||
*
|
||||
* http://sites.google.com/site/chitchatvmback/backdoor
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/vmware.h>
|
||||
|
||||
/**
|
||||
* Detect VMware presence
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int vmware_present ( void ) {
|
||||
uint32_t version;
|
||||
uint32_t magic;
|
||||
uint32_t product_type;
|
||||
|
||||
/* Perform backdoor call */
|
||||
vmware_cmd_get_version ( &version, &magic, &product_type );
|
||||
|
||||
/* Check for VMware presence */
|
||||
if ( magic != VMW_MAGIC ) {
|
||||
DBGC ( VMW_MAGIC, "VMware not present\n" );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
DBGC ( VMW_MAGIC, "VMware product type %04x version %08x detected\n",
|
||||
product_type, version );
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/bigint.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
/**
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint32_t multiplicand_element;
|
||||
uint32_t multiplier_element;
|
||||
uint32_t *result_elements;
|
||||
uint32_t discard_a;
|
||||
uint32_t discard_d;
|
||||
long index;
|
||||
|
||||
/* Zero result */
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
* resulting double-element into the result,
|
||||
* carrying as necessary. The carry can
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mull %4\n\t"
|
||||
"addl %%eax, (%5,%2,4)\n\t"
|
||||
"adcl %%edx, 4(%5,%2,4)\n\t"
|
||||
"\n1:\n\t"
|
||||
"adcl $0, 8(%5,%2,4)\n\t"
|
||||
"inc %2\n\t"
|
||||
/* Does not affect CF */
|
||||
"jc 1b\n\t"
|
||||
: "=&a" ( discard_a ),
|
||||
"=&d" ( discard_d ),
|
||||
"=&r" ( index )
|
||||
: "0" ( multiplicand_element ),
|
||||
"g" ( multiplier_element ),
|
||||
"r" ( result_elements ),
|
||||
"2" ( 0 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
#ifndef _BITS_BIGINT_H
|
||||
#define _BITS_BIGINT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/** Element of a big integer */
|
||||
typedef uint32_t bigint_element_t;
|
||||
|
||||
/**
|
||||
* Initialise big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer to initialise
|
||||
* @v size Number of elements
|
||||
* @v data Raw data
|
||||
* @v len Length of raw data
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_init_raw ( uint32_t *value0, unsigned int size,
|
||||
const void *data, size_t len ) {
|
||||
long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
|
||||
void *discard_D;
|
||||
long discard_c;
|
||||
|
||||
/* Copy raw data in reverse order, padding with zeros */
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"movb -1(%2,%1), %%al\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t"
|
||||
"xorl %%eax, %%eax\n\t"
|
||||
"mov %3, %1\n\t"
|
||||
"rep stosb\n\t"
|
||||
: "=&D" ( discard_D ), "=&c" ( discard_c )
|
||||
: "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
|
||||
"1" ( len )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add big integers
|
||||
*
|
||||
* @v addend0 Element 0 of big integer to add
|
||||
* @v value0 Element 0 of big integer to be added to
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
|
||||
unsigned int size ) {
|
||||
long index;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
|
||||
"\n1:\n\t"
|
||||
"lodsl\n\t"
|
||||
"adcl %%eax, (%3,%0,4)\n\t"
|
||||
"inc %0\n\t" /* Does not affect CF */
|
||||
"loop 1b\n\t"
|
||||
: "=&r" ( index ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
: "r" ( value0 ), "1" ( addend0 ), "2" ( size )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract big integers
|
||||
*
|
||||
* @v subtrahend0 Element 0 of big integer to subtract
|
||||
* @v value0 Element 0 of big integer to be subtracted from
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
|
||||
unsigned int size ) {
|
||||
long index;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
|
||||
"\n1:\n\t"
|
||||
"lodsl\n\t"
|
||||
"sbbl %%eax, (%3,%0,4)\n\t"
|
||||
"inc %0\n\t" /* Does not affect CF */
|
||||
"loop 1b\n\t"
|
||||
: "=&r" ( index ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
: "r" ( value0 ), "1" ( subtrahend0 ),
|
||||
"2" ( size )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate big integer left
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
|
||||
long index;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
|
||||
"\n1:\n\t"
|
||||
"rcll $1, (%2,%0,4)\n\t"
|
||||
"inc %0\n\t" /* Does not affect CF */
|
||||
"loop 1b\n\t"
|
||||
: "=&r" ( index ), "=&c" ( discard_c )
|
||||
: "r" ( value0 ), "1" ( size ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate big integer right
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "clc\n\t"
|
||||
"\n1:\n\t"
|
||||
"rcrl $1, -4(%1,%0,4)\n\t"
|
||||
"loop 1b\n\t"
|
||||
: "=&c" ( discard_c )
|
||||
: "r" ( value0 ), "0" ( size ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if big integer is equal to zero
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @ret is_zero Big integer is equal to zero
|
||||
*/
|
||||
static inline __attribute__ (( always_inline, pure )) int
|
||||
bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
|
||||
void *discard_D;
|
||||
long discard_c;
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Set ZF */
|
||||
"repe scasl\n\t"
|
||||
"sete %b0\n\t"
|
||||
: "=&a" ( result ), "=&D" ( discard_D ),
|
||||
"=&c" ( discard_c )
|
||||
: "1" ( value0 ), "2" ( size ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare big integers
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v reference0 Element 0 of reference big integer
|
||||
* @v size Number of elements
|
||||
* @ret geq Big integer is greater than or equal to the reference
|
||||
*/
|
||||
static inline __attribute__ (( always_inline, pure )) int
|
||||
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
|
||||
unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( const void * ) value0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *reference =
|
||||
( ( const void * ) reference0 );
|
||||
void *discard_S;
|
||||
void *discard_D;
|
||||
long discard_c;
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ ( "std\n\t"
|
||||
"\n1:\n\t"
|
||||
"lodsl\n\t"
|
||||
"scasl\n\t"
|
||||
"loope 1b\n\t"
|
||||
"setae %b0\n\t"
|
||||
"cld\n\t"
|
||||
: "=q" ( result ), "=&S" ( discard_S ),
|
||||
"=&D" ( discard_D ), "=&c" ( discard_c )
|
||||
: "0" ( 0 ), "1" ( &value->element[ size - 1 ] ),
|
||||
"2" ( &reference->element[ size - 1 ] ),
|
||||
"3" ( size )
|
||||
: "eax" );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if bit is set in big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @v bit Bit to test
|
||||
* @ret is_set Bit is set
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
|
||||
unsigned int bit ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( const void * ) value0 );
|
||||
unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
|
||||
unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
|
||||
|
||||
return ( value->element[index] & ( 1 << subindex ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find highest bit set in big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer
|
||||
* @v size Number of elements
|
||||
* @ret max_bit Highest bit set + 1 (or 0 if no bits set)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) int
|
||||
bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
|
||||
long discard_c;
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"bsrl -4(%2,%1,4), %0\n\t"
|
||||
"loopz 1b\n\t"
|
||||
"rol %1\n\t" /* Does not affect ZF */
|
||||
"rol %1\n\t"
|
||||
"leal 1(%k0,%k1,8), %k0\n\t"
|
||||
"jnz 2f\n\t"
|
||||
"xor %0, %0\n\t"
|
||||
"\n2:\n\t"
|
||||
: "=&r" ( result ), "=&c" ( discard_c )
|
||||
: "r" ( value0 ), "1" ( size ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow big integer
|
||||
*
|
||||
* @v source0 Element 0 of source big integer
|
||||
* @v source_size Number of elements in source big integer
|
||||
* @v dest0 Element 0 of destination big integer
|
||||
* @v dest_size Number of elements in destination big integer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
|
||||
uint32_t *dest0, unsigned int dest_size ) {
|
||||
long pad_size = ( dest_size - source_size );
|
||||
void *discard_D;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "rep movsl\n\t"
|
||||
"xorl %%eax, %%eax\n\t"
|
||||
"mov %3, %2\n\t"
|
||||
"rep stosl\n\t"
|
||||
: "=&D" ( discard_D ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
: "g" ( pad_size ), "0" ( dest0 ),
|
||||
"1" ( source0 ), "2" ( source_size )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrink big integer
|
||||
*
|
||||
* @v source0 Element 0 of source big integer
|
||||
* @v source_size Number of elements in source big integer
|
||||
* @v dest0 Element 0 of destination big integer
|
||||
* @v dest_size Number of elements in destination big integer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
|
||||
uint32_t *dest0, unsigned int dest_size ) {
|
||||
void *discard_D;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "rep movsl\n\t"
|
||||
: "=&D" ( discard_D ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
: "0" ( dest0 ), "1" ( source0 ),
|
||||
"2" ( dest_size )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise big integer
|
||||
*
|
||||
* @v value0 Element 0 of big integer to finalise
|
||||
* @v size Number of elements
|
||||
* @v out Output buffer
|
||||
* @v len Length of output buffer
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
void *out, size_t len ) {
|
||||
void *discard_D;
|
||||
long discard_c;
|
||||
|
||||
/* Copy raw data in reverse order */
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"movb -1(%2,%1), %%al\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t"
|
||||
: "=&D" ( discard_D ), "=&c" ( discard_c )
|
||||
: "r" ( value0 ), "0" ( out ), "1" ( len )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *value0, unsigned int size );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
@@ -22,4 +22,4 @@ _linux_start:
|
||||
movq $__NR_exit, %rax
|
||||
syscall
|
||||
|
||||
.size _start, . - _start
|
||||
.size _linux_start, . - _linux_start
|
||||
|
||||
@@ -1,22 +1,47 @@
|
||||
#ifndef _BITS_BYTESWAP_H
|
||||
#define _BITS_BYTESWAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Byte-order swapping functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint16_t
|
||||
__bswap_variable_16 ( uint16_t x ) {
|
||||
__asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_16s ( uint16_t *x ) {
|
||||
__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint32_t
|
||||
__bswap_variable_32 ( uint32_t x ) {
|
||||
__asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_32s ( uint32_t *x ) {
|
||||
__asm__ ( "bswapl %k0" : "=r" ( *x ) : "0" ( *x ) );
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline, const )) uint64_t
|
||||
__bswap_variable_64 ( uint64_t x ) {
|
||||
__asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) );
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
__bswap_64s ( uint64_t *x ) {
|
||||
__asm__ ( "bswapq %q0" : "=r" ( *x ) : "0" ( *x ) );
|
||||
}
|
||||
|
||||
#endif /* _BITS_BYTESWAP_H */
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_ENTROPY_H
|
||||
#define _BITS_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86_64-specific entropy API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#endif /* _BITS_ENTROPY_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_TIME_H
|
||||
#define _BITS_TIME_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86_64-specific time API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#endif /* _BITS_TIME_H */
|
||||
+16
-16
@@ -71,21 +71,24 @@ REQUIRE_OBJECT ( serial_console );
|
||||
#ifdef CONSOLE_DIRECT_VGA
|
||||
REQUIRE_OBJECT ( video_subr );
|
||||
#endif
|
||||
#ifdef CONSOLE_BTEXT
|
||||
REQUIRE_OBJECT ( btext );
|
||||
#endif
|
||||
#ifdef CONSOLE_PC_KBD
|
||||
REQUIRE_OBJECT ( pc_kbd );
|
||||
#endif
|
||||
#ifdef CONSOLE_SYSLOG
|
||||
REQUIRE_OBJECT ( syslog );
|
||||
#endif
|
||||
#ifdef CONSOLE_SYSLOGS
|
||||
REQUIRE_OBJECT ( syslogs );
|
||||
#endif
|
||||
#ifdef CONSOLE_EFI
|
||||
REQUIRE_OBJECT ( efi_console );
|
||||
#endif
|
||||
#ifdef CONSOLE_LINUX
|
||||
REQUIRE_OBJECT ( linux_console );
|
||||
#endif
|
||||
#ifdef CONSOLE_VMWARE
|
||||
REQUIRE_OBJECT ( vmconsole );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in all requested network protocols
|
||||
@@ -122,9 +125,6 @@ REQUIRE_OBJECT ( https );
|
||||
#ifdef DOWNLOAD_PROTO_FTP
|
||||
REQUIRE_OBJECT ( ftp );
|
||||
#endif
|
||||
#ifdef DOWNLOAD_PROTO_TFTM
|
||||
REQUIRE_OBJECT ( tftm );
|
||||
#endif
|
||||
#ifdef DOWNLOAD_PROTO_SLAM
|
||||
REQUIRE_OBJECT ( slam );
|
||||
#endif
|
||||
@@ -155,18 +155,9 @@ REQUIRE_OBJECT ( nbi );
|
||||
#ifdef IMAGE_ELF
|
||||
REQUIRE_OBJECT ( elfboot );
|
||||
#endif
|
||||
#ifdef IMAGE_FREEBSD
|
||||
REQUIRE_OBJECT ( freebsd );
|
||||
#endif
|
||||
#ifdef IMAGE_MULTIBOOT
|
||||
REQUIRE_OBJECT ( multiboot );
|
||||
#endif
|
||||
#ifdef IMAGE_AOUT
|
||||
REQUIRE_OBJECT ( aout );
|
||||
#endif
|
||||
#ifdef IMAGE_WINCE
|
||||
REQUIRE_OBJECT ( wince );
|
||||
#endif
|
||||
#ifdef IMAGE_PXE
|
||||
REQUIRE_OBJECT ( pxe_image );
|
||||
#endif
|
||||
@@ -214,12 +205,18 @@ REQUIRE_OBJECT ( route_cmd );
|
||||
#ifdef IMAGE_CMD
|
||||
REQUIRE_OBJECT ( image_cmd );
|
||||
#endif
|
||||
#ifdef IMAGE_TRUST_CMD
|
||||
REQUIRE_OBJECT ( image_trust_cmd );
|
||||
#endif
|
||||
#ifdef DHCP_CMD
|
||||
REQUIRE_OBJECT ( dhcp_cmd );
|
||||
#endif
|
||||
#ifdef SANBOOT_CMD
|
||||
REQUIRE_OBJECT ( sanboot_cmd );
|
||||
#endif
|
||||
#ifdef MENU_CMD
|
||||
REQUIRE_OBJECT ( menu_cmd );
|
||||
#endif
|
||||
#ifdef LOGIN_CMD
|
||||
REQUIRE_OBJECT ( login_cmd );
|
||||
#endif
|
||||
@@ -274,13 +271,16 @@ REQUIRE_OBJECT ( tap );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in relevant BOFM entry points
|
||||
* Drag in relevant sideband entry points
|
||||
*/
|
||||
#ifdef CONFIG_BOFM
|
||||
#ifdef BOFM_EFI
|
||||
REQUIRE_OBJECT ( efi_bofm );
|
||||
#endif /* BOFM_EFI */
|
||||
#endif /* CONFIG_BOFM */
|
||||
#ifdef VMWARE_SETTINGS
|
||||
REQUIRE_OBJECT ( guestinfo );
|
||||
#endif /* VMWARE_SETTINGS */
|
||||
|
||||
/*
|
||||
* Drag in selected keyboard map
|
||||
|
||||
@@ -17,12 +17,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
//#define CONSOLE_PCBIOS /* Default BIOS console */
|
||||
//#define CONSOLE_SERIAL /* Serial port */
|
||||
//#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */
|
||||
//#define CONSOLE_BTEXT /* Who knows what this does? */
|
||||
//#define CONSOLE_PC_KBD /* Direct access to PC keyboard */
|
||||
//#define CONSOLE_SYSLOG /* Syslog console */
|
||||
//#define CONSOLE_SYSLOGS /* Encrypted syslog console */
|
||||
//#define CONSOLE_VMWARE /* VMware logfile console */
|
||||
|
||||
#define KEYBOARD_MAP us
|
||||
|
||||
#define LOG_LEVEL LOG_NONE
|
||||
|
||||
#include <config/local/console.h>
|
||||
|
||||
#endif /* CONFIG_CONSOLE_H */
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#define SMBIOS_EFI
|
||||
#define SANBOOT_NULL
|
||||
#define BOFM_EFI
|
||||
#define ENTROPY_NULL
|
||||
#define TIME_NULL
|
||||
|
||||
#define IMAGE_EFI /* EFI image support */
|
||||
#define IMAGE_SCRIPT /* iPXE script image support */
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#define NAP_LINUX
|
||||
#define SMBIOS_LINUX
|
||||
#define SANBOOT_NULL
|
||||
#define ENTROPY_LINUX
|
||||
#define TIME_LINUX
|
||||
|
||||
#define DRIVERS_LINUX
|
||||
|
||||
|
||||
@@ -18,13 +18,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define UMALLOC_MEMTOP
|
||||
#define SMBIOS_PCBIOS
|
||||
#define SANBOOT_PCBIOS
|
||||
#define ENTROPY_RTC
|
||||
#define TIME_RTC
|
||||
|
||||
#define IMAGE_ELF /* ELF image support */
|
||||
#define IMAGE_MULTIBOOT /* MultiBoot image support */
|
||||
#define IMAGE_PXE /* PXE image support */
|
||||
#define IMAGE_SCRIPT /* iPXE script image support */
|
||||
#define IMAGE_BZIMAGE /* Linux bzImage image support */
|
||||
#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
|
||||
|
||||
#define PXE_STACK /* PXE stack in iPXE - required for PXELINUX */
|
||||
#define PXE_MENU /* PXE menu booting */
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_ENTROPY_H
|
||||
#define CONFIG_ENTROPY_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Entropy API configuration
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <config/defaults.h>
|
||||
|
||||
#include <config/local/entropy.h>
|
||||
|
||||
#endif /* CONFIG_ENTROPY_H */
|
||||
@@ -58,7 +58,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
|
||||
#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
|
||||
|
||||
/*
|
||||
@@ -95,10 +94,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*/
|
||||
#undef IMAGE_NBI /* NBI image support */
|
||||
//#define IMAGE_ELF /* ELF image support */
|
||||
#undef IMAGE_FREEBSD /* FreeBSD kernel image support */
|
||||
#undef IMAGE_MULTIBOOT /* MultiBoot image support */
|
||||
#undef IMAGE_AOUT /* a.out image support */
|
||||
#undef IMAGE_WINCE /* WinCE image support */
|
||||
//#define IMAGE_PXE /* PXE image support */
|
||||
//#define IMAGE_SCRIPT /* iPXE script image support */
|
||||
//#define IMAGE_BZIMAGE /* Linux bzImage image support */
|
||||
@@ -119,6 +115,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define IMAGE_CMD /* Image management commands */
|
||||
#undef DHCP_CMD /* DHCP management commands */
|
||||
#define SANBOOT_CMD /* SAN boot commands */
|
||||
#undef MENU_CMD /* Menu commands */
|
||||
#undef LOGIN_CMD /* Login command */
|
||||
#undef TIME_CMD /* Time commands */
|
||||
#undef DIGEST_CMD /* Image crypto digest commands */
|
||||
@@ -126,6 +123,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#undef VLAN_CMD /* VLAN commands */
|
||||
#undef PXE_CMD /* PXE commands */
|
||||
#undef REBOOT_CMD /* Reboot command */
|
||||
#define IMAGE_TRUST_CMD /* Image trust management commands */
|
||||
|
||||
/*
|
||||
* ROM-specific options
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
//#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */
|
||||
//#define VMWARE_SETTINGS /* VMware GuestInfo settings */
|
||||
|
||||
#endif /* CONFIG_SIDEBAND_H */
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_TIME_H
|
||||
#define CONFIG_TIME_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Time API configuration
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <config/defaults.h>
|
||||
|
||||
#include <config/local/time.h>
|
||||
|
||||
#endif /* CONFIG_TIME_H */
|
||||
-5039
File diff suppressed because it is too large
Load Diff
+6
-1
@@ -7,6 +7,9 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** Current console usage */
|
||||
int console_usage = CONSOLE_USAGE_STDOUT;
|
||||
|
||||
/**
|
||||
* Write a single character to each console device.
|
||||
*
|
||||
@@ -26,7 +29,9 @@ void putchar ( int character ) {
|
||||
putchar ( '\r' );
|
||||
|
||||
for_each_table_entry ( console, CONSOLES ) {
|
||||
if ( ( ! console->disabled ) && console->putchar )
|
||||
if ( ( ! console->disabled ) &&
|
||||
( console_usage & console->usage ) &&
|
||||
console->putchar )
|
||||
console->putchar ( character );
|
||||
}
|
||||
}
|
||||
|
||||
+37
-16
@@ -21,17 +21,38 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/console.h>
|
||||
|
||||
/**
|
||||
* Print debug message
|
||||
*
|
||||
* @v fmt Format string
|
||||
* @v ... Arguments
|
||||
*/
|
||||
void dbg_printf ( const char *fmt, ... ) {
|
||||
int saved_usage;
|
||||
va_list args;
|
||||
|
||||
/* Mark console as in use for debugging messages */
|
||||
saved_usage = console_set_usage ( CONSOLE_USAGE_DEBUG );
|
||||
|
||||
/* Print message */
|
||||
va_start ( args, fmt );
|
||||
vprintf ( fmt, args );
|
||||
va_end ( args );
|
||||
|
||||
/* Restore console usage */
|
||||
console_set_usage ( saved_usage );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause until a key is pressed
|
||||
*
|
||||
*/
|
||||
void dbg_pause ( void ) {
|
||||
printf ( "\nPress a key..." );
|
||||
dbg_printf ( "\nPress a key..." );
|
||||
getchar();
|
||||
printf ( "\r \r" );
|
||||
dbg_printf ( "\r \r" );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,9 +60,9 @@ void dbg_pause ( void ) {
|
||||
*
|
||||
*/
|
||||
void dbg_more ( void ) {
|
||||
printf ( "---more---" );
|
||||
dbg_printf ( "---more---" );
|
||||
getchar();
|
||||
printf ( "\r \r" );
|
||||
dbg_printf ( "\r \r" );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,27 +79,27 @@ static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data,
|
||||
unsigned int i;
|
||||
uint8_t byte;
|
||||
|
||||
printf ( "%08lx :", ( dispaddr + offset ) );
|
||||
dbg_printf ( "%08lx :", ( dispaddr + offset ) );
|
||||
for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
|
||||
if ( i >= len ) {
|
||||
printf ( " " );
|
||||
dbg_printf ( " " );
|
||||
continue;
|
||||
}
|
||||
printf ( "%c%02x",
|
||||
( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
|
||||
dbg_printf ( "%c%02x",
|
||||
( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
|
||||
}
|
||||
printf ( " : " );
|
||||
dbg_printf ( " : " );
|
||||
for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
|
||||
if ( i >= len ) {
|
||||
printf ( " " );
|
||||
dbg_printf ( " " );
|
||||
continue;
|
||||
}
|
||||
byte = bytes[i];
|
||||
if ( ( byte < 0x20 ) || ( byte >= 0x7f ) )
|
||||
byte = '.';
|
||||
printf ( "%c", byte );
|
||||
dbg_printf ( "%c", byte );
|
||||
}
|
||||
printf ( "\n" );
|
||||
dbg_printf ( "\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,8 +179,8 @@ static int dbg_autocolour ( unsigned long stream ) {
|
||||
* @v stream Message stream ID
|
||||
*/
|
||||
void dbg_autocolourise ( unsigned long stream ) {
|
||||
printf ( "\033[%dm",
|
||||
( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
|
||||
dbg_printf ( "\033[%dm",
|
||||
( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,5 +188,5 @@ void dbg_autocolourise ( unsigned long stream ) {
|
||||
*
|
||||
*/
|
||||
void dbg_decolourise ( void ) {
|
||||
printf ( "\033[0m" );
|
||||
dbg_printf ( "\033[0m" );
|
||||
}
|
||||
|
||||
+13
-1
@@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/xfer.h>
|
||||
#include <ipxe/open.h>
|
||||
@@ -73,6 +74,15 @@ static void downloader_free ( struct refcnt *refcnt ) {
|
||||
*/
|
||||
static void downloader_finished ( struct downloader *downloader, int rc ) {
|
||||
|
||||
/* Log download status */
|
||||
if ( rc == 0 ) {
|
||||
syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
|
||||
downloader->image->name );
|
||||
} else {
|
||||
syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
|
||||
downloader->image->name, strerror ( rc ) );
|
||||
}
|
||||
|
||||
/* Shut down interfaces */
|
||||
intf_shutdown ( &downloader->xfer, rc );
|
||||
intf_shutdown ( &downloader->job, rc );
|
||||
@@ -101,7 +111,7 @@ static int downloader_ensure_size ( struct downloader *downloader,
|
||||
if ( ! new_buffer ) {
|
||||
DBGC ( downloader, "Downloader %p could not extend buffer to "
|
||||
"%zd bytes\n", downloader, len );
|
||||
return -ENOBUFS;
|
||||
return -ENOSPC;
|
||||
}
|
||||
downloader->image->data = new_buffer;
|
||||
downloader->image->len = len;
|
||||
@@ -173,6 +183,8 @@ static int downloader_xfer_deliver ( struct downloader *downloader,
|
||||
|
||||
done:
|
||||
free_iob ( iobuf );
|
||||
if ( rc != 0 )
|
||||
downloader_finished ( downloader, rc );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+106
-22
@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <libgen.h>
|
||||
#include <syslog.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/umalloc.h>
|
||||
#include <ipxe/uri.h>
|
||||
@@ -36,12 +37,28 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*
|
||||
*/
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EACCES_UNTRUSTED \
|
||||
__einfo_error ( EINFO_EACCES_UNTRUSTED )
|
||||
#define EINFO_EACCES_UNTRUSTED \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted image" )
|
||||
#define EACCES_PERMANENT \
|
||||
__einfo_error ( EINFO_EACCES_PERMANENT )
|
||||
#define EINFO_EACCES_PERMANENT \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x02, "Trust requirement is permanent" )
|
||||
|
||||
/** List of registered images */
|
||||
struct list_head images = LIST_HEAD_INIT ( images );
|
||||
|
||||
/** Currently-executing image */
|
||||
struct image *current_image;
|
||||
|
||||
/** Current image trust requirement */
|
||||
static int require_trusted_images = 0;
|
||||
|
||||
/** Prevent changes to image trust requirement */
|
||||
static int require_trusted_images_permanent = 0;
|
||||
|
||||
/**
|
||||
* Free executable image
|
||||
*
|
||||
@@ -50,48 +67,70 @@ struct image *current_image;
|
||||
static void free_image ( struct refcnt *refcnt ) {
|
||||
struct image *image = container_of ( refcnt, struct image, refcnt );
|
||||
|
||||
DBGC ( image, "IMAGE %s freed\n", image->name );
|
||||
free ( image->name );
|
||||
free ( image->cmdline );
|
||||
uri_put ( image->uri );
|
||||
ufree ( image->data );
|
||||
image_put ( image->replacement );
|
||||
free ( image );
|
||||
DBGC ( image, "IMAGE %s freed\n", image->name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate executable image
|
||||
*
|
||||
* @v uri URI, or NULL
|
||||
* @ret image Executable image
|
||||
*/
|
||||
struct image * alloc_image ( void ) {
|
||||
struct image * alloc_image ( struct uri *uri ) {
|
||||
const char *name;
|
||||
struct image *image;
|
||||
int rc;
|
||||
|
||||
/* Allocate image */
|
||||
image = zalloc ( sizeof ( *image ) );
|
||||
if ( image ) {
|
||||
ref_init ( &image->refcnt, free_image );
|
||||
if ( ! image )
|
||||
goto err_alloc;
|
||||
|
||||
/* Initialise image */
|
||||
ref_init ( &image->refcnt, free_image );
|
||||
if ( uri ) {
|
||||
image->uri = uri_get ( uri );
|
||||
if ( uri->path ) {
|
||||
name = basename ( ( char * ) uri->path );
|
||||
if ( ( rc = image_set_name ( image, name ) ) != 0 )
|
||||
goto err_set_name;
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
|
||||
err_set_name:
|
||||
image_put ( image );
|
||||
err_alloc:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set image URI
|
||||
* Set image name
|
||||
*
|
||||
* @v image Image
|
||||
* @v URI New image URI
|
||||
*
|
||||
* If no name is set, the name will be updated to the base name of the
|
||||
* URI path (if any).
|
||||
* @v name New image name
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
void image_set_uri ( struct image *image, struct uri *uri ) {
|
||||
const char *path = uri->path;
|
||||
int image_set_name ( struct image *image, const char *name ) {
|
||||
char *name_copy;
|
||||
|
||||
/* Replace URI reference */
|
||||
uri_put ( image->uri );
|
||||
image->uri = uri_get ( uri );
|
||||
/* Duplicate name */
|
||||
name_copy = strdup ( name );
|
||||
if ( ! name_copy )
|
||||
return -ENOMEM;
|
||||
|
||||
/* Set name if none already specified */
|
||||
if ( path && ( ! image->name[0] ) )
|
||||
image_set_name ( image, basename ( ( char * ) path ) );
|
||||
/* Replace existing name */
|
||||
free ( image->name );
|
||||
image->name = name_copy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,11 +160,14 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
|
||||
*/
|
||||
int register_image ( struct image *image ) {
|
||||
static unsigned int imgindex = 0;
|
||||
char name[8]; /* "imgXXXX" */
|
||||
int rc;
|
||||
|
||||
/* Create image name if it doesn't already have one */
|
||||
if ( ! image->name[0] ) {
|
||||
snprintf ( image->name, sizeof ( image->name ), "img%d",
|
||||
imgindex++ );
|
||||
if ( ! image->name ) {
|
||||
snprintf ( name, sizeof ( name ), "img%d", imgindex++ );
|
||||
if ( ( rc = image_set_name ( image, name ) ) != 0 )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Avoid ending up with multiple "selected" images on
|
||||
@@ -228,6 +270,12 @@ int image_exec ( struct image *image ) {
|
||||
if ( ( rc = image_select ( image ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Check that image is trusted (if applicable) */
|
||||
if ( require_trusted_images && ! ( image->flags & IMAGE_TRUSTED ) ) {
|
||||
DBGC ( image, "IMAGE %s is not trusted\n", image->name );
|
||||
return -EACCES_UNTRUSTED;
|
||||
}
|
||||
|
||||
/* Switch current working directory to be that of the image itself */
|
||||
old_cwuri = uri_get ( cwuri );
|
||||
churi ( image->uri );
|
||||
@@ -241,6 +289,9 @@ int image_exec ( struct image *image ) {
|
||||
*/
|
||||
current_image = image_get ( image );
|
||||
|
||||
/* Record boot attempt */
|
||||
syslog ( LOG_NOTICE, "Executing \"%s\"\n", image->name );
|
||||
|
||||
/* Try executing the image */
|
||||
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
|
||||
DBGC ( image, "IMAGE %s could not execute: %s\n",
|
||||
@@ -248,6 +299,15 @@ int image_exec ( struct image *image ) {
|
||||
/* Do not return yet; we still have clean-up to do */
|
||||
}
|
||||
|
||||
/* Record result of boot attempt */
|
||||
if ( rc == 0 ) {
|
||||
syslog ( LOG_NOTICE, "Execution of \"%s\" completed\n",
|
||||
image->name );
|
||||
} else {
|
||||
syslog ( LOG_ERR, "Execution of \"%s\" failed: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
}
|
||||
|
||||
/* Pick up replacement image before we drop the original
|
||||
* image's temporary reference. The replacement image must
|
||||
* already be registered, so we don't need to hold a temporary
|
||||
@@ -269,8 +329,8 @@ int image_exec ( struct image *image ) {
|
||||
|
||||
/* Tail-recurse into replacement image, if one exists */
|
||||
if ( replacement ) {
|
||||
DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
|
||||
image->name, replacement->name );
|
||||
DBGC ( image, "IMAGE <freed> replacing self with IMAGE %s\n",
|
||||
replacement->name );
|
||||
if ( ( rc = image_exec ( replacement ) ) != 0 )
|
||||
return rc;
|
||||
}
|
||||
@@ -355,3 +415,27 @@ struct image * image_find_selected ( void ) {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change image trust requirement
|
||||
*
|
||||
* @v require_trusted Require trusted images
|
||||
* @v permanent Make trust requirement permanent
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_set_trust ( int require_trusted, int permanent ) {
|
||||
|
||||
/* Update trust requirement, if permitted to do so */
|
||||
if ( ! require_trusted_images_permanent ) {
|
||||
require_trusted_images = require_trusted;
|
||||
require_trusted_images_permanent = permanent;
|
||||
}
|
||||
|
||||
/* Fail if we attempted to change the trust requirement but
|
||||
* were not permitted to do so.
|
||||
*/
|
||||
if ( require_trusted_images != require_trusted )
|
||||
return -EACCES_PERMANENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Line-based console
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ipxe/ansiesc.h>
|
||||
#include <ipxe/lineconsole.h>
|
||||
|
||||
/**
|
||||
* Print a character to a line-based console
|
||||
*
|
||||
* @v character Character to be printed
|
||||
* @ret print Print line
|
||||
*/
|
||||
size_t line_putchar ( struct line_console *line, int character ) {
|
||||
|
||||
/* Strip ANSI escape sequences */
|
||||
character = ansiesc_process ( &line->ctx, character );
|
||||
if ( character < 0 )
|
||||
return 0;
|
||||
|
||||
/* Ignore carriage return */
|
||||
if ( character == '\r' )
|
||||
return 0;
|
||||
|
||||
/* Treat newline as a terminator */
|
||||
if ( character == '\n' )
|
||||
character = 0;
|
||||
|
||||
/* Add character to buffer */
|
||||
line->buffer[line->index++] = character;
|
||||
|
||||
/* Do nothing more unless we reach end-of-line (or end-of-buffer) */
|
||||
if ( ( character != 0 ) &&
|
||||
( line->index < ( line->len - 1 /* NUL */ ) ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset to start of buffer */
|
||||
line->index = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* System logger
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <ipxe/console.h>
|
||||
|
||||
/**
|
||||
* Write message to system log
|
||||
*
|
||||
* @v fmt Format string
|
||||
* @v args Arguments
|
||||
*/
|
||||
void log_vprintf ( const char *fmt, va_list args ) {
|
||||
int saved_usage;
|
||||
|
||||
/* Mark console as in use for log messages */
|
||||
saved_usage = console_set_usage ( CONSOLE_USAGE_LOG );
|
||||
|
||||
/* Print message */
|
||||
vprintf ( fmt, args );
|
||||
|
||||
/* Restore console usage */
|
||||
console_set_usage ( saved_usage );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write message to system log
|
||||
*
|
||||
* @v fmt Format string
|
||||
* @v ... Arguments
|
||||
*/
|
||||
void log_printf ( const char *fmt, ... ) {
|
||||
va_list args;
|
||||
|
||||
va_start ( args, fmt );
|
||||
log_vprintf ( fmt, args );
|
||||
va_end ( args );
|
||||
}
|
||||
+92
-11
@@ -105,11 +105,36 @@ static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
|
||||
static inline void valgrind_make_blocks_defined ( void ) {
|
||||
struct memory_block *block;
|
||||
|
||||
if ( RUNNING_ON_VALGRIND > 0 ) {
|
||||
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks,
|
||||
sizeof ( free_blocks ) );
|
||||
list_for_each_entry ( block, &free_blocks, list )
|
||||
VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
|
||||
if ( RUNNING_ON_VALGRIND <= 0 )
|
||||
return;
|
||||
|
||||
/* Traverse free block list, marking each block structure as
|
||||
* defined. Some contortions are necessary to avoid errors
|
||||
* from list_check().
|
||||
*/
|
||||
|
||||
/* Mark block list itself as defined */
|
||||
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks, sizeof ( free_blocks ) );
|
||||
|
||||
/* Mark areas accessed by list_check() as defined */
|
||||
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.prev->next,
|
||||
sizeof ( free_blocks.prev->next ) );
|
||||
VALGRIND_MAKE_MEM_DEFINED ( free_blocks.next,
|
||||
sizeof ( *free_blocks.next ) );
|
||||
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->next->prev,
|
||||
sizeof ( free_blocks.next->next->prev ) );
|
||||
|
||||
/* Mark each block in list as defined */
|
||||
list_for_each_entry ( block, &free_blocks, list ) {
|
||||
|
||||
/* Mark block as defined */
|
||||
VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
|
||||
|
||||
/* Mark areas accessed by list_check() as defined */
|
||||
VALGRIND_MAKE_MEM_DEFINED ( block->list.next,
|
||||
sizeof ( *block->list.next ) );
|
||||
VALGRIND_MAKE_MEM_DEFINED ( &block->list.next->next->prev,
|
||||
sizeof ( block->list.next->next->prev ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,14 +144,45 @@ static inline void valgrind_make_blocks_defined ( void ) {
|
||||
*/
|
||||
static inline void valgrind_make_blocks_noaccess ( void ) {
|
||||
struct memory_block *block;
|
||||
struct memory_block *tmp;
|
||||
struct memory_block *prev = NULL;
|
||||
|
||||
if ( RUNNING_ON_VALGRIND > 0 ) {
|
||||
list_for_each_entry_safe ( block, tmp, &free_blocks, list )
|
||||
VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) );
|
||||
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks,
|
||||
sizeof ( free_blocks ) );
|
||||
if ( RUNNING_ON_VALGRIND <= 0 )
|
||||
return;
|
||||
|
||||
/* Traverse free block list, marking each block structure as
|
||||
* inaccessible. Some contortions are necessary to avoid
|
||||
* errors from list_check().
|
||||
*/
|
||||
|
||||
/* Mark each block in list as inaccessible */
|
||||
list_for_each_entry ( block, &free_blocks, list ) {
|
||||
|
||||
/* Mark previous block (if any) as inaccessible. (Current
|
||||
* block will be accessed by list_check().)
|
||||
*/
|
||||
if ( prev )
|
||||
VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
|
||||
prev = block;
|
||||
|
||||
/* At the end of the list, list_check() will end up
|
||||
* accessing the first list item. Temporarily mark
|
||||
* this area as defined.
|
||||
*/
|
||||
VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->prev,
|
||||
sizeof ( free_blocks.next->prev ) );
|
||||
}
|
||||
/* Mark last block (if any) as inaccessible */
|
||||
if ( prev )
|
||||
VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
|
||||
|
||||
/* Mark as inaccessible the area that was temporarily marked
|
||||
* as defined to avoid errors from list_check().
|
||||
*/
|
||||
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks.next->prev,
|
||||
sizeof ( free_blocks.next->prev ) );
|
||||
|
||||
/* Mark block list itself as inaccessible */
|
||||
VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,6 +200,18 @@ static unsigned int discard_cache ( void ) {
|
||||
return discarded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard all cached data
|
||||
*
|
||||
*/
|
||||
static void discard_all_cache ( void ) {
|
||||
unsigned int discarded;
|
||||
|
||||
do {
|
||||
discarded = discard_cache();
|
||||
} while ( discarded );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a memory block
|
||||
*
|
||||
@@ -458,6 +526,19 @@ struct init_fn heap_init_fn __init_fn ( INIT_EARLY ) = {
|
||||
.initialise = init_heap,
|
||||
};
|
||||
|
||||
/**
|
||||
* Discard all cached data on shutdown
|
||||
*
|
||||
*/
|
||||
static void shutdown_cache ( int booting __unused ) {
|
||||
discard_all_cache();
|
||||
}
|
||||
|
||||
/** Memory allocator shutdown function */
|
||||
struct startup_fn heap_startup_fn __startup_fn ( STARTUP_EARLY ) = {
|
||||
.shutdown = shutdown_cache,
|
||||
};
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
/**
|
||||
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Menu selection
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/menu.h>
|
||||
|
||||
/** List of all menus */
|
||||
static LIST_HEAD ( menus );
|
||||
|
||||
/**
|
||||
* Create menu
|
||||
*
|
||||
* @v name Menu name, or NULL
|
||||
* @v title Menu title, or NULL
|
||||
* @ret menu Menu, or NULL on failure
|
||||
*/
|
||||
struct menu * create_menu ( const char *name, const char *title ) {
|
||||
size_t name_len;
|
||||
size_t title_len;
|
||||
size_t len;
|
||||
struct menu *menu;
|
||||
char *name_copy;
|
||||
char *title_copy;
|
||||
|
||||
/* Destroy any existing menu of this name */
|
||||
menu = find_menu ( name );
|
||||
if ( menu )
|
||||
destroy_menu ( menu );
|
||||
|
||||
/* Use empty title if none given */
|
||||
if ( ! title )
|
||||
title = "";
|
||||
|
||||
/* Allocate menu */
|
||||
name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
|
||||
title_len = ( strlen ( title ) + 1 /* NUL */ );
|
||||
len = ( sizeof ( *menu ) + name_len + title_len );
|
||||
menu = zalloc ( len );
|
||||
if ( ! menu )
|
||||
return NULL;
|
||||
name_copy = ( ( void * ) ( menu + 1 ) );
|
||||
title_copy = ( name_copy + name_len );
|
||||
|
||||
/* Initialise menu */
|
||||
if ( name ) {
|
||||
strcpy ( name_copy, name );
|
||||
menu->name = name_copy;
|
||||
}
|
||||
strcpy ( title_copy, title );
|
||||
menu->title = title_copy;
|
||||
INIT_LIST_HEAD ( &menu->items );
|
||||
|
||||
/* Add to list of menus */
|
||||
list_add_tail ( &menu->list, &menus );
|
||||
|
||||
DBGC ( menu, "MENU %s created with title \"%s\"\n",
|
||||
menu->name, menu->title );
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add menu item
|
||||
*
|
||||
* @v menu Menu
|
||||
* @v label Label, or NULL
|
||||
* @v text Text, or NULL
|
||||
* @v shortcut Shortcut key
|
||||
* @v is_default Item is the default item
|
||||
* @ret item Menu item, or NULL on failure
|
||||
*/
|
||||
struct menu_item * add_menu_item ( struct menu *menu, const char *label,
|
||||
const char *text, int shortcut,
|
||||
int is_default ) {
|
||||
size_t label_len;
|
||||
size_t text_len;
|
||||
size_t len;
|
||||
struct menu_item *item;
|
||||
char *label_copy;
|
||||
char *text_copy;
|
||||
|
||||
/* Use empty text if none given */
|
||||
if ( ! text )
|
||||
text = "";
|
||||
|
||||
/* Allocate item */
|
||||
label_len = ( label ? ( strlen ( label ) + 1 /* NUL */ ) : 0 );
|
||||
text_len = ( strlen ( text ) + 1 /* NUL */ );
|
||||
len = ( sizeof ( *item ) + label_len + text_len );
|
||||
item = zalloc ( len );
|
||||
if ( ! item )
|
||||
return NULL;
|
||||
label_copy = ( ( void * ) ( item + 1 ) );
|
||||
text_copy = ( label_copy + label_len );
|
||||
|
||||
/* Initialise item */
|
||||
if ( label ) {
|
||||
strcpy ( label_copy, label );
|
||||
item->label = label_copy;
|
||||
}
|
||||
strcpy ( text_copy, text );
|
||||
item->text = text_copy;
|
||||
item->shortcut = shortcut;
|
||||
item->is_default = is_default;
|
||||
|
||||
/* Add to list of items */
|
||||
list_add_tail ( &item->list, &menu->items );
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy menu
|
||||
*
|
||||
* @v menu Menu
|
||||
*/
|
||||
void destroy_menu ( struct menu *menu ) {
|
||||
struct menu_item *item;
|
||||
struct menu_item *tmp;
|
||||
|
||||
/* Remove from list of menus */
|
||||
list_del ( &menu->list );
|
||||
|
||||
/* Free items */
|
||||
list_for_each_entry_safe ( item, tmp, &menu->items, list ) {
|
||||
list_del ( &item->list );
|
||||
free ( item );
|
||||
}
|
||||
|
||||
/* Free menu */
|
||||
free ( menu );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find menu
|
||||
*
|
||||
* @v name Menu name, or NULL
|
||||
* @ret menu Menu, or NULL if not found
|
||||
*/
|
||||
struct menu * find_menu ( const char *name ) {
|
||||
struct menu *menu;
|
||||
|
||||
list_for_each_entry ( menu, &menus, list ) {
|
||||
if ( ( menu->name == name ) ||
|
||||
( strcmp ( menu->name, name ) == 0 ) ) {
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -35,8 +35,17 @@ int inet_aton ( const char *cp, struct in_addr *inp ) {
|
||||
|
||||
unsigned long strtoul ( const char *p, char **endp, int base ) {
|
||||
unsigned long ret = 0;
|
||||
int negative = 0;
|
||||
unsigned int charval;
|
||||
|
||||
while ( isspace ( *p ) )
|
||||
p++;
|
||||
|
||||
if ( *p == '-' ) {
|
||||
negative = 1;
|
||||
p++;
|
||||
}
|
||||
|
||||
base = strtoul_base ( &p, base );
|
||||
|
||||
while ( 1 ) {
|
||||
@@ -47,6 +56,9 @@ unsigned long strtoul ( const char *p, char **endp, int base ) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if ( negative )
|
||||
ret = -ret;
|
||||
|
||||
if ( endp )
|
||||
*endp = ( char * ) p;
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Nonexistent time source
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ipxe/time.h>
|
||||
|
||||
PROVIDE_TIME_INLINE ( null, time_now );
|
||||
+31
-11
@@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/menu.h>
|
||||
#include <ipxe/parseopt.h>
|
||||
|
||||
/** @file
|
||||
@@ -115,21 +115,22 @@ int parse_netdev ( const char *text, struct net_device **netdev ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse image name
|
||||
* Parse menu name
|
||||
*
|
||||
* @v text Text
|
||||
* @ret image Image
|
||||
* @ret menu Menu
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int parse_image ( const char *text, struct image **image ) {
|
||||
int parse_menu ( const char *text, struct menu **menu ) {
|
||||
|
||||
/* Sanity check */
|
||||
assert ( text != NULL );
|
||||
|
||||
/* Find network device */
|
||||
*image = find_image ( text );
|
||||
if ( ! *image ) {
|
||||
printf ( "\"%s\": no such image\n", text );
|
||||
/* Find menu */
|
||||
*menu = find_menu ( text );
|
||||
if ( ! *menu ) {
|
||||
if ( text ) {
|
||||
printf ( "\"%s\": no such menu\n", text );
|
||||
} else {
|
||||
printf ( "No default menu\n" );
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -151,6 +152,25 @@ int parse_flag ( const char *text __unused, int *flag ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse key
|
||||
*
|
||||
* @v text Text
|
||||
* @ret key Key
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int parse_key ( const char *text, unsigned int *key ) {
|
||||
|
||||
/* Interpret single characters as being a literal key character */
|
||||
if ( text[0] && ! text[1] ) {
|
||||
*key = text[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, interpret as an integer */
|
||||
return parse_integer ( text, key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print command usage message
|
||||
*
|
||||
|
||||
@@ -34,7 +34,6 @@ FILE_LICENCE ( GPL2_ONLY );
|
||||
#define CODE_STATUS "alpha"
|
||||
#define CODE_VERSION "0.1.3"
|
||||
#include <pcmcia-opts.h>
|
||||
#include <ipxe/console.h>
|
||||
#include <ipxe/init.h>
|
||||
|
||||
int sockets; /* AHTODO: Phase this out! */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/serial.h>
|
||||
#include <ipxe/console.h>
|
||||
#include <config/console.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
@@ -8,6 +9,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* Set default console usage if applicable */
|
||||
#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) )
|
||||
#undef CONSOLE_SERIAL
|
||||
#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
|
||||
#endif
|
||||
|
||||
struct console_driver serial_console __console_driver;
|
||||
|
||||
static void serial_console_init ( void ) {
|
||||
@@ -21,6 +28,7 @@ struct console_driver serial_console __console_driver = {
|
||||
.getchar = serial_getc,
|
||||
.iskey = serial_ischar,
|
||||
.disabled = 1,
|
||||
.usage = CONSOLE_SERIAL,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+384
-241
@@ -676,6 +676,46 @@ int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
|
||||
return fetch_setting ( settings, setting, NULL, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch copy of setting
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v data Buffer to allocate and fill with setting data
|
||||
* @ret len Length of setting, or negative error
|
||||
*
|
||||
* The caller is responsible for eventually freeing the allocated
|
||||
* buffer.
|
||||
*
|
||||
* To allow the caller to distinguish between a non-existent setting
|
||||
* and an error in allocating memory for the copy, this function will
|
||||
* return success (and a NULL buffer pointer) for a non-existent
|
||||
* setting.
|
||||
*/
|
||||
int fetch_setting_copy ( struct settings *settings, struct setting *setting,
|
||||
void **data ) {
|
||||
int len;
|
||||
int check_len = 0;
|
||||
|
||||
/* Avoid returning uninitialised data on error */
|
||||
*data = NULL;
|
||||
|
||||
/* Fetch setting length, and return success if non-existent */
|
||||
len = fetch_setting_len ( settings, setting );
|
||||
if ( len < 0 )
|
||||
return 0;
|
||||
|
||||
/* Allocate buffer */
|
||||
*data = malloc ( len );
|
||||
if ( ! *data )
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fetch setting */
|
||||
check_len = fetch_setting ( settings, setting, *data, len );
|
||||
assert ( check_len == len );
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch value of string setting
|
||||
*
|
||||
@@ -776,6 +816,41 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
|
||||
return fetch_ipv4_array_setting ( settings, setting, inp, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract numeric value of setting
|
||||
*
|
||||
* @v raw Raw setting data
|
||||
* @v len Length of raw setting data
|
||||
* @ret signed_value Value, when interpreted as a signed integer
|
||||
* @ret unsigned_value Value, when interpreted as an unsigned integer
|
||||
* @ret len Length of setting, or negative error
|
||||
*/
|
||||
static int numeric_setting_value ( const void *raw, size_t len,
|
||||
signed long *signed_value,
|
||||
unsigned long *unsigned_value ) {
|
||||
const uint8_t *unsigned_bytes = raw;
|
||||
const int8_t *signed_bytes = raw;
|
||||
int is_negative;
|
||||
unsigned int i;
|
||||
uint8_t byte;
|
||||
|
||||
/* Range check */
|
||||
if ( len > sizeof ( long ) )
|
||||
return -ERANGE;
|
||||
|
||||
/* Convert to host-ordered longs */
|
||||
is_negative = ( len && ( signed_bytes[0] < 0 ) );
|
||||
*signed_value = ( is_negative ? -1L : 0 );
|
||||
*unsigned_value = 0;
|
||||
for ( i = 0 ; i < len ; i++ ) {
|
||||
byte = unsigned_bytes[i];
|
||||
*signed_value = ( ( *signed_value << 8 ) | byte );
|
||||
*unsigned_value = ( ( *unsigned_value << 8 ) | byte );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch value of signed integer setting
|
||||
*
|
||||
@@ -786,30 +861,20 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
|
||||
*/
|
||||
int fetch_int_setting ( struct settings *settings, struct setting *setting,
|
||||
long *value ) {
|
||||
union {
|
||||
uint8_t u8[ sizeof ( long ) ];
|
||||
int8_t s8[ sizeof ( long ) ];
|
||||
} buf;
|
||||
unsigned long dummy;
|
||||
long tmp;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
/* Avoid returning uninitialised data on error */
|
||||
*value = 0;
|
||||
|
||||
/* Fetch raw (network-ordered, variable-length) setting */
|
||||
len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
|
||||
len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) );
|
||||
if ( len < 0 )
|
||||
return len;
|
||||
if ( len > ( int ) sizeof ( buf ) )
|
||||
return -ERANGE;
|
||||
|
||||
/* Convert to host-ordered signed long */
|
||||
*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
|
||||
for ( i = 0 ; i < len ; i++ ) {
|
||||
*value = ( ( *value << 8 ) | buf.u8[i] );
|
||||
}
|
||||
|
||||
return len;
|
||||
/* Extract numeric value */
|
||||
return numeric_setting_value ( &tmp, len, value, &dummy );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -822,22 +887,20 @@ int fetch_int_setting ( struct settings *settings, struct setting *setting,
|
||||
*/
|
||||
int fetch_uint_setting ( struct settings *settings, struct setting *setting,
|
||||
unsigned long *value ) {
|
||||
long svalue;
|
||||
signed long dummy;
|
||||
long tmp;
|
||||
int len;
|
||||
|
||||
/* Avoid returning uninitialised data on error */
|
||||
*value = 0;
|
||||
|
||||
/* Fetch as a signed long */
|
||||
len = fetch_int_setting ( settings, setting, &svalue );
|
||||
/* Fetch raw (network-ordered, variable-length) setting */
|
||||
len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) );
|
||||
if ( len < 0 )
|
||||
return len;
|
||||
|
||||
/* Mask off sign-extended bits */
|
||||
assert ( len <= ( int ) sizeof ( long ) );
|
||||
*value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) );
|
||||
|
||||
return len;
|
||||
/* Extract numeric value */
|
||||
return numeric_setting_value ( &tmp, len, &dummy, value );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -929,27 +992,83 @@ int setting_cmp ( struct setting *a, struct setting *b ) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Store value of typed setting
|
||||
* Fetch and format value of setting
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v type Settings type
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
int fetchf_setting ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
int raw_len;
|
||||
int check_len;
|
||||
int rc;
|
||||
|
||||
/* Fetch raw value */
|
||||
raw_len = fetch_setting_len ( settings, setting );
|
||||
if ( raw_len < 0 ) {
|
||||
rc = raw_len;
|
||||
return rc;
|
||||
} else {
|
||||
uint8_t raw[raw_len];
|
||||
|
||||
/* Fetch raw value */
|
||||
check_len = fetch_setting ( settings, setting, raw,
|
||||
sizeof ( raw ) );
|
||||
if ( check_len < 0 )
|
||||
return check_len;
|
||||
assert ( check_len == raw_len );
|
||||
|
||||
/* Format value */
|
||||
return setting->type->format ( raw, sizeof ( raw ), buf, len );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store formatted value of setting
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v type Settings type
|
||||
* @v value Formatted setting data, or NULL
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int storef_setting ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
int raw_len;
|
||||
int check_len;
|
||||
int rc;
|
||||
|
||||
/* NULL value implies deletion. Avoid imposing the burden of
|
||||
* checking for NULL values on each typed setting's storef()
|
||||
* method.
|
||||
*/
|
||||
/* NULL value implies deletion */
|
||||
if ( ! value )
|
||||
return delete_setting ( settings, setting );
|
||||
|
||||
return setting->type->storef ( settings, setting, value );
|
||||
|
||||
/* Parse formatted value */
|
||||
raw_len = setting->type->parse ( value, NULL, 0 );
|
||||
if ( raw_len < 0 ) {
|
||||
rc = raw_len;
|
||||
return rc;
|
||||
} else {
|
||||
uint8_t raw[raw_len];
|
||||
|
||||
/* Parse formatted value */
|
||||
check_len = setting->type->parse ( value, raw, sizeof ( raw ) );
|
||||
assert ( check_len == raw_len );
|
||||
|
||||
/* Store raw value */
|
||||
return store_setting ( settings, setting, raw, sizeof ( raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Named settings
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find named setting
|
||||
*
|
||||
@@ -1176,302 +1295,334 @@ int fetchf_named_setting ( const char *name,
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse and store value of string setting
|
||||
* Parse string setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @ret rc Return status code
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_string ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
return store_setting ( settings, setting, value, strlen ( value ) );
|
||||
static int parse_string_setting ( const char *value, void *buf, size_t len ) {
|
||||
size_t raw_len = strlen ( value ); /* Exclude terminating NUL */
|
||||
|
||||
/* Copy string to buffer */
|
||||
if ( len > raw_len )
|
||||
len = raw_len;
|
||||
memcpy ( buf, value, len );
|
||||
|
||||
return raw_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of string setting
|
||||
* Format string setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_string ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
return fetch_string_setting ( settings, setting, buf, len );
|
||||
static int format_string_setting ( const void *raw, size_t raw_len, char *buf,
|
||||
size_t len ) {
|
||||
|
||||
/* Copy string to buffer, and terminate */
|
||||
memset ( buf, 0, len );
|
||||
if ( len > raw_len )
|
||||
len = raw_len;
|
||||
memcpy ( buf, raw, len );
|
||||
|
||||
return raw_len;
|
||||
}
|
||||
|
||||
/** A string setting type */
|
||||
struct setting_type setting_type_string __setting_type = {
|
||||
.name = "string",
|
||||
.storef = storef_string,
|
||||
.fetchf = fetchf_string,
|
||||
.parse = parse_string_setting,
|
||||
.format = format_string_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse and store value of URI-encoded string setting
|
||||
* Parse URI-encoded string setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @ret rc Return status code
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_uristring ( struct settings *settings,
|
||||
struct setting *setting,
|
||||
const char *value ) {
|
||||
char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */
|
||||
size_t len;
|
||||
static int parse_uristring_setting ( const char *value, void *buf,
|
||||
size_t len ) {
|
||||
char tmp[ len + 1 /* NUL */ ];
|
||||
size_t raw_len;
|
||||
|
||||
len = uri_decode ( value, buf, sizeof ( buf ) );
|
||||
return store_setting ( settings, setting, buf, len );
|
||||
/* Decode to temporary buffer (including NUL) */
|
||||
raw_len = uri_decode ( value, tmp, sizeof ( tmp ) );
|
||||
|
||||
/* Copy to output buffer (excluding NUL) */
|
||||
if ( len > raw_len )
|
||||
len = raw_len;
|
||||
memcpy ( buf, tmp, len );
|
||||
|
||||
return raw_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of URI-encoded string setting
|
||||
* Format URI-encoded string setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_uristring ( struct settings *settings,
|
||||
struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
ssize_t raw_len;
|
||||
static int format_uristring_setting ( const void *raw, size_t raw_len,
|
||||
char *buf, size_t len ) {
|
||||
char tmp[ raw_len + 1 /* NUL */ ];
|
||||
|
||||
/* We need to always retrieve the full raw string to know the
|
||||
* length of the encoded string.
|
||||
*/
|
||||
raw_len = fetch_setting ( settings, setting, NULL, 0 );
|
||||
if ( raw_len < 0 )
|
||||
return raw_len;
|
||||
/* Copy to temporary buffer and terminate */
|
||||
memcpy ( tmp, raw, raw_len );
|
||||
tmp[raw_len] = '\0';
|
||||
|
||||
{
|
||||
char raw_buf[ raw_len + 1 ];
|
||||
|
||||
fetch_string_setting ( settings, setting, raw_buf,
|
||||
sizeof ( raw_buf ) );
|
||||
return uri_encode ( raw_buf, buf, len, URI_FRAGMENT );
|
||||
}
|
||||
/* Encode directly into output buffer */
|
||||
return uri_encode ( tmp, buf, len, URI_FRAGMENT );
|
||||
}
|
||||
|
||||
/** A URI-encoded string setting type */
|
||||
struct setting_type setting_type_uristring __setting_type = {
|
||||
.name = "uristring",
|
||||
.storef = storef_uristring,
|
||||
.fetchf = fetchf_uristring,
|
||||
.parse = parse_uristring_setting,
|
||||
.format = format_uristring_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse and store value of IPv4 address setting
|
||||
* Parse IPv4 address setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @ret rc Return status code
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_ipv4 ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) {
|
||||
struct in_addr ipv4;
|
||||
|
||||
/* Parse IPv4 address */
|
||||
if ( inet_aton ( value, &ipv4 ) == 0 )
|
||||
return -EINVAL;
|
||||
return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
|
||||
|
||||
/* Copy to buffer */
|
||||
if ( len > sizeof ( ipv4 ) )
|
||||
len = sizeof ( ipv4 );
|
||||
memcpy ( buf, &ipv4, len );
|
||||
|
||||
return ( sizeof ( ipv4 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of IPv4 address setting
|
||||
* Format IPv4 address setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
struct in_addr ipv4;
|
||||
int raw_len;
|
||||
static int format_ipv4_setting ( const void *raw, size_t raw_len, char *buf,
|
||||
size_t len ) {
|
||||
const struct in_addr *ipv4 = raw;
|
||||
|
||||
if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0)
|
||||
return raw_len;
|
||||
return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) );
|
||||
if ( raw_len < sizeof ( *ipv4 ) )
|
||||
return -EINVAL;
|
||||
return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) );
|
||||
}
|
||||
|
||||
/** An IPv4 address setting type */
|
||||
struct setting_type setting_type_ipv4 __setting_type = {
|
||||
.name = "ipv4",
|
||||
.storef = storef_ipv4,
|
||||
.fetchf = fetchf_ipv4,
|
||||
.parse = parse_ipv4_setting,
|
||||
.format = format_ipv4_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse and store value of integer setting
|
||||
* Parse integer setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @v size Integer size, in bytes
|
||||
* @ret rc Return status code
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_int ( struct settings *settings, struct setting *setting,
|
||||
const char *value, unsigned int size ) {
|
||||
static int parse_int_setting ( const char *value, void *buf, size_t len,
|
||||
unsigned int size ) {
|
||||
union {
|
||||
uint32_t num;
|
||||
uint8_t bytes[4];
|
||||
} u;
|
||||
char *endp;
|
||||
|
||||
/* Parse value */
|
||||
u.num = htonl ( strtoul ( value, &endp, 0 ) );
|
||||
if ( *endp )
|
||||
return -EINVAL;
|
||||
return store_setting ( settings, setting,
|
||||
&u.bytes[ sizeof ( u ) - size ], size );
|
||||
|
||||
/* Copy to buffer */
|
||||
if ( len > size )
|
||||
len = size;
|
||||
memcpy ( buf, &u.bytes[ sizeof ( u ) - size ], len );
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and store value of 8-bit integer setting
|
||||
* Parse 8-bit integer setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @v size Integer size, in bytes
|
||||
* @ret rc Return status code
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_int8 ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
return storef_int ( settings, setting, value, 1 );
|
||||
static int parse_int8_setting ( const char *value, void *buf, size_t len ) {
|
||||
return parse_int_setting ( value, buf, len, sizeof ( uint8_t ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and store value of 16-bit integer setting
|
||||
* Parse 16-bit integer setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @v size Integer size, in bytes
|
||||
* @ret rc Return status code
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_int16 ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
return storef_int ( settings, setting, value, 2 );
|
||||
static int parse_int16_setting ( const char *value, void *buf, size_t len ) {
|
||||
return parse_int_setting ( value, buf, len, sizeof ( uint16_t ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and store value of 32-bit integer setting
|
||||
* Parse 32-bit integer setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @v size Integer size, in bytes
|
||||
* @ret rc Return status code
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_int32 ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
return storef_int ( settings, setting, value, 4 );
|
||||
static int parse_int32_setting ( const char *value, void *buf, size_t len ) {
|
||||
return parse_int_setting ( value, buf, len, sizeof ( uint32_t ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of signed integer setting
|
||||
* Format signed integer setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_int ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
long value;
|
||||
int rc;
|
||||
static int format_int_setting ( const void *raw, size_t raw_len, char *buf,
|
||||
size_t len ) {
|
||||
signed long value;
|
||||
unsigned long dummy;
|
||||
int check_len;
|
||||
|
||||
if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
|
||||
return rc;
|
||||
/* Extract numeric value */
|
||||
check_len = numeric_setting_value ( raw, raw_len, &value, &dummy );
|
||||
if ( check_len < 0 )
|
||||
return check_len;
|
||||
assert ( check_len == ( int ) raw_len );
|
||||
|
||||
/* Format value */
|
||||
return snprintf ( buf, len, "%ld", value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of unsigned integer setting
|
||||
* Format unsigned integer setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_uint ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
static int format_uint_setting ( const void *raw, size_t raw_len, char *buf,
|
||||
size_t len ) {
|
||||
signed long dummy;
|
||||
unsigned long value;
|
||||
int rc;
|
||||
int check_len;
|
||||
|
||||
if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
|
||||
return rc;
|
||||
/* Extract numeric value */
|
||||
check_len = numeric_setting_value ( raw, raw_len, &dummy, &value );
|
||||
if ( check_len < 0 )
|
||||
return check_len;
|
||||
assert ( check_len == ( int ) raw_len );
|
||||
|
||||
/* Format value */
|
||||
return snprintf ( buf, len, "%#lx", value );
|
||||
}
|
||||
|
||||
/** A signed 8-bit integer setting type */
|
||||
struct setting_type setting_type_int8 __setting_type = {
|
||||
.name = "int8",
|
||||
.storef = storef_int8,
|
||||
.fetchf = fetchf_int,
|
||||
.parse = parse_int8_setting,
|
||||
.format = format_int_setting,
|
||||
};
|
||||
|
||||
/** A signed 16-bit integer setting type */
|
||||
struct setting_type setting_type_int16 __setting_type = {
|
||||
.name = "int16",
|
||||
.storef = storef_int16,
|
||||
.fetchf = fetchf_int,
|
||||
.parse = parse_int16_setting,
|
||||
.format = format_int_setting,
|
||||
};
|
||||
|
||||
/** A signed 32-bit integer setting type */
|
||||
struct setting_type setting_type_int32 __setting_type = {
|
||||
.name = "int32",
|
||||
.storef = storef_int32,
|
||||
.fetchf = fetchf_int,
|
||||
.parse = parse_int32_setting,
|
||||
.format = format_int_setting,
|
||||
};
|
||||
|
||||
/** An unsigned 8-bit integer setting type */
|
||||
struct setting_type setting_type_uint8 __setting_type = {
|
||||
.name = "uint8",
|
||||
.storef = storef_int8,
|
||||
.fetchf = fetchf_uint,
|
||||
.parse = parse_int8_setting,
|
||||
.format = format_uint_setting,
|
||||
};
|
||||
|
||||
/** An unsigned 16-bit integer setting type */
|
||||
struct setting_type setting_type_uint16 __setting_type = {
|
||||
.name = "uint16",
|
||||
.storef = storef_int16,
|
||||
.fetchf = fetchf_uint,
|
||||
.parse = parse_int16_setting,
|
||||
.format = format_uint_setting,
|
||||
};
|
||||
|
||||
/** An unsigned 32-bit integer setting type */
|
||||
struct setting_type setting_type_uint32 __setting_type = {
|
||||
.name = "uint32",
|
||||
.storef = storef_int32,
|
||||
.fetchf = fetchf_uint,
|
||||
.parse = parse_int32_setting,
|
||||
.format = format_uint_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse and store value of hex string setting
|
||||
* Parse hex string setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @ret rc Return status code
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_hex ( struct settings *settings, struct setting *setting,
|
||||
const char *value ) {
|
||||
static int parse_hex_setting ( const char *value, void *buf, size_t len ) {
|
||||
char *ptr = ( char * ) value;
|
||||
uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
|
||||
unsigned int len = 0;
|
||||
uint8_t *bytes = buf;
|
||||
unsigned int count = 0;
|
||||
uint8_t byte;
|
||||
|
||||
while ( 1 ) {
|
||||
bytes[len++] = strtoul ( ptr, &ptr, 16 );
|
||||
byte = strtoul ( ptr, &ptr, 16 );
|
||||
if ( count++ < len )
|
||||
*bytes++ = byte;
|
||||
switch ( *ptr ) {
|
||||
case '\0' :
|
||||
return store_setting ( settings, setting, bytes, len );
|
||||
return count;
|
||||
case ':' :
|
||||
case '-' :
|
||||
ptr++;
|
||||
@@ -1483,128 +1634,112 @@ static int storef_hex ( struct settings *settings, struct setting *setting,
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of hex string setting
|
||||
* Format hex string setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @v delimiter Byte delimiter
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_hex ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len, const char *delimiter ) {
|
||||
int raw_len;
|
||||
int check_len;
|
||||
static int format_hex_setting ( const void *raw, size_t raw_len, char *buf,
|
||||
size_t len, const char *delimiter ) {
|
||||
const uint8_t *bytes = raw;
|
||||
int used = 0;
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
raw_len = fetch_setting_len ( settings, setting );
|
||||
if ( raw_len < 0 )
|
||||
return raw_len;
|
||||
|
||||
{
|
||||
uint8_t raw[raw_len];
|
||||
|
||||
check_len = fetch_setting ( settings, setting, raw,
|
||||
sizeof ( raw ) );
|
||||
if ( check_len < 0 )
|
||||
return check_len;
|
||||
assert ( check_len == raw_len );
|
||||
|
||||
if ( len )
|
||||
buf[0] = 0; /* Ensure that a terminating NUL exists */
|
||||
for ( i = 0 ; i < raw_len ; i++ ) {
|
||||
used += ssnprintf ( ( buf + used ), ( len - used ),
|
||||
"%s%02x", ( used ? delimiter : "" ),
|
||||
raw[i] );
|
||||
}
|
||||
return used;
|
||||
if ( len )
|
||||
buf[0] = 0; /* Ensure that a terminating NUL exists */
|
||||
for ( i = 0 ; i < raw_len ; i++ ) {
|
||||
used += ssnprintf ( ( buf + used ), ( len - used ),
|
||||
"%s%02x", ( used ? delimiter : "" ),
|
||||
bytes[i] );
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of hex string setting (using colon delimiter)
|
||||
* Format hex string setting value (using colon delimiter)
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_hex_colon ( struct settings *settings,
|
||||
struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
return fetchf_hex ( settings, setting, buf, len, ":" );
|
||||
static int format_hex_colon_setting ( const void *raw, size_t raw_len,
|
||||
char *buf, size_t len ) {
|
||||
return format_hex_setting ( raw, raw_len, buf, len, ":" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of hex string setting (using hyphen delimiter)
|
||||
* Format hex string setting value (using hyphen delimiter)
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_hex_hyphen ( struct settings *settings,
|
||||
struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
return fetchf_hex ( settings, setting, buf, len, "-" );
|
||||
static int format_hex_hyphen_setting ( const void *raw, size_t raw_len,
|
||||
char *buf, size_t len ) {
|
||||
return format_hex_setting ( raw, raw_len, buf, len, "-" );
|
||||
}
|
||||
|
||||
/** A hex-string setting (colon-delimited) */
|
||||
struct setting_type setting_type_hex __setting_type = {
|
||||
.name = "hex",
|
||||
.storef = storef_hex,
|
||||
.fetchf = fetchf_hex_colon,
|
||||
.parse = parse_hex_setting,
|
||||
.format = format_hex_colon_setting,
|
||||
};
|
||||
|
||||
/** A hex-string setting (hyphen-delimited) */
|
||||
struct setting_type setting_type_hexhyp __setting_type = {
|
||||
.name = "hexhyp",
|
||||
.storef = storef_hex,
|
||||
.fetchf = fetchf_hex_hyphen,
|
||||
.parse = parse_hex_setting,
|
||||
.format = format_hex_hyphen_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse and store value of UUID setting
|
||||
* Parse UUID setting value
|
||||
*
|
||||
* @v settings Settings block
|
||||
* @v setting Setting to store
|
||||
* @v value Formatted setting data
|
||||
* @ret rc Return status code
|
||||
* @v value Formatted setting value
|
||||
* @v buf Buffer to contain raw value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of raw value, or negative error
|
||||
*/
|
||||
static int storef_uuid ( struct settings *settings __unused,
|
||||
struct setting *setting __unused,
|
||||
const char *value __unused ) {
|
||||
static int parse_uuid_setting ( const char *value __unused,
|
||||
void *buf __unused, size_t len __unused ) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and format value of UUID setting
|
||||
* Format UUID setting value
|
||||
*
|
||||
* @v settings Settings block, or NULL to search all blocks
|
||||
* @v setting Setting to fetch
|
||||
* @v raw Raw setting value
|
||||
* @v raw_len Length of raw setting value
|
||||
* @v buf Buffer to contain formatted value
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int fetchf_uuid ( struct settings *settings, struct setting *setting,
|
||||
char *buf, size_t len ) {
|
||||
union uuid uuid;
|
||||
int raw_len;
|
||||
static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf,
|
||||
size_t len ) {
|
||||
const union uuid *uuid = raw;
|
||||
|
||||
if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0)
|
||||
return raw_len;
|
||||
return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
|
||||
/* Range check */
|
||||
if ( raw_len != sizeof ( *uuid ) )
|
||||
return -ERANGE;
|
||||
|
||||
/* Format value */
|
||||
return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
|
||||
}
|
||||
|
||||
/** UUID setting type */
|
||||
struct setting_type setting_type_uuid __setting_type = {
|
||||
.name = "uuid",
|
||||
.storef = storef_uuid,
|
||||
.fetchf = fetchf_uuid,
|
||||
.parse = parse_uuid_setting,
|
||||
.format = format_uuid_setting,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
@@ -1703,6 +1838,14 @@ struct setting hostname_setting __setting ( SETTING_HOST ) = {
|
||||
.type = &setting_type_string,
|
||||
};
|
||||
|
||||
/** TFTP server setting */
|
||||
struct setting next_server_setting __setting ( SETTING_BOOT ) = {
|
||||
.name = "next-server",
|
||||
.description = "TFTP server",
|
||||
.tag = DHCP_EB_SIADDR,
|
||||
.type = &setting_type_ipv4,
|
||||
};
|
||||
|
||||
/** Filename setting */
|
||||
struct setting filename_setting __setting ( SETTING_BOOT ) = {
|
||||
.name = "filename",
|
||||
|
||||
@@ -29,8 +29,17 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*/
|
||||
unsigned long long strtoull ( const char *p, char **endp, int base ) {
|
||||
unsigned long long ret = 0;
|
||||
int negative = 0;
|
||||
unsigned int charval;
|
||||
|
||||
while ( isspace ( *p ) )
|
||||
p++;
|
||||
|
||||
if ( *p == '-' ) {
|
||||
negative = 1;
|
||||
p++;
|
||||
}
|
||||
|
||||
base = strtoul_base ( &p, base );
|
||||
|
||||
while ( 1 ) {
|
||||
@@ -41,6 +50,9 @@ unsigned long long strtoull ( const char *p, char **endp, int base ) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if ( negative )
|
||||
ret = -ret;
|
||||
|
||||
if ( endp )
|
||||
*endp = ( char * ) p;
|
||||
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Date and time
|
||||
*
|
||||
* POSIX:2008 section 4.15 defines "seconds since the Epoch" as an
|
||||
* abstract measure approximating the number of seconds that have
|
||||
* elapsed since the Epoch, excluding leap seconds. The formula given
|
||||
* is
|
||||
*
|
||||
* tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
|
||||
* (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
|
||||
* ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
|
||||
*
|
||||
* This calculation assumes that leap years occur in each year that is
|
||||
* either divisible by 4 but not divisible by 100, or is divisible by
|
||||
* 400.
|
||||
*/
|
||||
|
||||
/** Days of week (for debugging) */
|
||||
static const char *weekdays[] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether or not year is a leap year
|
||||
*
|
||||
* @v tm_year Years since 1900
|
||||
* @v is_leap_year Year is a leap year
|
||||
*/
|
||||
static int is_leap_year ( int tm_year ) {
|
||||
int leap_year = 0;
|
||||
|
||||
if ( ( tm_year % 4 ) == 0 )
|
||||
leap_year = 1;
|
||||
if ( ( tm_year % 100 ) == 0 )
|
||||
leap_year = 0;
|
||||
if ( ( tm_year % 400 ) == 100 )
|
||||
leap_year = 1;
|
||||
|
||||
return leap_year;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of leap years since 1900
|
||||
*
|
||||
* @v tm_year Years since 1900
|
||||
* @v num_leap_years Number of leap years
|
||||
*/
|
||||
static int leap_years_to_end ( int tm_year ) {
|
||||
int leap_years = 0;
|
||||
|
||||
leap_years += ( tm_year / 4 );
|
||||
leap_years -= ( tm_year / 100 );
|
||||
leap_years += ( ( tm_year + 300 ) / 400 );
|
||||
|
||||
return leap_years;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate day of week
|
||||
*
|
||||
* @v tm_year Years since 1900
|
||||
* @v tm_mon Month of year [0,11]
|
||||
* @v tm_day Day of month [1,31]
|
||||
*/
|
||||
static int day_of_week ( int tm_year, int tm_mon, int tm_mday ) {
|
||||
static const uint8_t offset[12] =
|
||||
{ 1, 4, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
|
||||
int pseudo_year = tm_year;
|
||||
|
||||
if ( tm_mon < 2 )
|
||||
pseudo_year--;
|
||||
return ( ( pseudo_year + leap_years_to_end ( pseudo_year ) +
|
||||
offset[tm_mon] + tm_mday ) % 7 );
|
||||
}
|
||||
|
||||
/** Days from start of year until start of months (in non-leap years) */
|
||||
static const uint16_t days_to_month_start[] =
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
|
||||
/**
|
||||
* Calculate seconds since the Epoch
|
||||
*
|
||||
* @v tm Broken-down time
|
||||
* @ret time Seconds since the Epoch
|
||||
*/
|
||||
time_t mktime ( struct tm *tm ) {
|
||||
int days_since_epoch;
|
||||
int seconds_since_day;
|
||||
time_t seconds;
|
||||
|
||||
/* Calculate day of year */
|
||||
tm->tm_yday = ( ( tm->tm_mday - 1 ) +
|
||||
days_to_month_start[ tm->tm_mon ] );
|
||||
if ( ( tm->tm_mon >= 2 ) && is_leap_year ( tm->tm_year ) )
|
||||
tm->tm_yday++;
|
||||
|
||||
/* Calculate day of week */
|
||||
tm->tm_wday = day_of_week ( tm->tm_year, tm->tm_mon, tm->tm_mday );
|
||||
|
||||
/* Calculate seconds since the Epoch */
|
||||
days_since_epoch = ( tm->tm_yday + ( 365 * tm->tm_year ) - 25567 +
|
||||
leap_years_to_end ( tm->tm_year - 1 ) );
|
||||
seconds_since_day =
|
||||
( ( ( ( tm->tm_hour * 60 ) + tm->tm_min ) * 60 ) + tm->tm_sec );
|
||||
seconds = ( ( ( ( time_t ) days_since_epoch ) * ( ( time_t ) 86400 ) ) +
|
||||
seconds_since_day );
|
||||
|
||||
DBGC ( &weekdays, "TIME %04d-%02d-%02d %02d:%02d:%02d => %lld (%s, "
|
||||
"day %d)\n", ( tm->tm_year + 1900 ), ( tm->tm_mon + 1 ),
|
||||
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, seconds,
|
||||
weekdays[ tm->tm_wday ], tm->tm_yday );
|
||||
|
||||
return seconds;
|
||||
}
|
||||
+1
-1
@@ -35,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* @v uuid UUID
|
||||
* @ret string UUID in canonical form
|
||||
*/
|
||||
char * uuid_ntoa ( union uuid *uuid ) {
|
||||
char * uuid_ntoa ( const union uuid *uuid ) {
|
||||
static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
|
||||
|
||||
sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
|
||||
|
||||
@@ -21,7 +21,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <ipxe/console.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/vsprintf.h>
|
||||
|
||||
|
||||
+19
-7
@@ -19,6 +19,7 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
@@ -297,17 +298,28 @@ int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) {
|
||||
*/
|
||||
int xfer_vprintf ( struct interface *intf, const char *format,
|
||||
va_list args ) {
|
||||
size_t len;
|
||||
va_list args_tmp;
|
||||
char *buf;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Create temporary string */
|
||||
va_copy ( args_tmp, args );
|
||||
len = vsnprintf ( NULL, 0, format, args );
|
||||
{
|
||||
char buf[len + 1];
|
||||
vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
|
||||
va_end ( args_tmp );
|
||||
return xfer_deliver_raw ( intf, buf, len );
|
||||
len = vasprintf ( &buf, format, args );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
goto err_asprintf;
|
||||
}
|
||||
va_end ( args_tmp );
|
||||
|
||||
/* Transmit string */
|
||||
if ( ( rc = xfer_deliver_raw ( intf, buf, len ) ) != 0 )
|
||||
goto err_deliver;
|
||||
|
||||
err_deliver:
|
||||
free ( buf );
|
||||
err_asprintf:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/xfer.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/xferbuf.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Data transfer buffer
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Finish using data transfer buffer
|
||||
*
|
||||
* @v xferbuf Data transfer buffer
|
||||
*/
|
||||
void xferbuf_done ( struct xfer_buffer *xferbuf ) {
|
||||
free ( xferbuf->data );
|
||||
xferbuf->data = NULL;
|
||||
xferbuf->len = 0;
|
||||
xferbuf->pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that data transfer buffer is large enough for the specified size
|
||||
*
|
||||
* @v xferbuf Data transfer buffer
|
||||
* @v len Required minimum size
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
|
||||
void *new_data;
|
||||
|
||||
/* If buffer is already large enough, do nothing */
|
||||
if ( len <= xferbuf->len )
|
||||
return 0;
|
||||
|
||||
/* Extend buffer */
|
||||
new_data = realloc ( xferbuf->data, len );
|
||||
if ( ! new_data ) {
|
||||
DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
|
||||
"%zd bytes\n", xferbuf, len );
|
||||
return -ENOSPC;
|
||||
}
|
||||
xferbuf->data = new_data;
|
||||
xferbuf->len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add received data to data transfer buffer
|
||||
*
|
||||
* @v xferbuf Data transfer buffer
|
||||
* @v iobuf I/O buffer
|
||||
* @v meta Data transfer metadata
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
|
||||
struct xfer_metadata *meta ) {
|
||||
size_t len;
|
||||
size_t max;
|
||||
int rc;
|
||||
|
||||
/* Calculate new buffer position */
|
||||
if ( meta->flags & XFER_FL_ABS_OFFSET )
|
||||
xferbuf->pos = 0;
|
||||
xferbuf->pos += meta->offset;
|
||||
|
||||
/* Ensure that we have enough buffer space for this data */
|
||||
len = iob_len ( iobuf );
|
||||
max = ( xferbuf->pos + len );
|
||||
if ( ( rc = xferbuf_ensure_size ( xferbuf, max ) ) != 0 )
|
||||
goto done;
|
||||
|
||||
/* Copy data to buffer */
|
||||
memcpy ( ( xferbuf->data + xferbuf->pos ), iobuf->data, len );
|
||||
|
||||
/* Update current buffer position */
|
||||
xferbuf->pos += len;
|
||||
|
||||
done:
|
||||
free_iob ( iobuf );
|
||||
return rc;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ int aes_wrap ( const void *kek, const void *src, void *dest, int nblk )
|
||||
cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
|
||||
|
||||
/* Set up */
|
||||
memset ( A, 0xA6, sizeof ( A ) );
|
||||
memset ( A, 0xA6, 8 );
|
||||
memmove ( dest + 8, src, nblk * 8 );
|
||||
|
||||
/* Wrap */
|
||||
|
||||
+221
-6
@@ -20,7 +20,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/tables.h>
|
||||
#include <ipxe/asn1.h>
|
||||
|
||||
/** @file
|
||||
@@ -42,12 +44,32 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
__einfo_error ( EINFO_EINVAL_ASN1_LEN )
|
||||
#define EINFO_EINVAL_ASN1_LEN \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
|
||||
#define EINVAL_ASN1_BOOLEAN \
|
||||
__einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
|
||||
#define EINFO_EINVAL_ASN1_BOOLEAN \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
|
||||
#define EINVAL_ASN1_INTEGER \
|
||||
__einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
|
||||
#define EINFO_EINVAL_ASN1_INTEGER \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
|
||||
|
||||
/**
|
||||
* Invalidate ASN.1 object cursor
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
*/
|
||||
void asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
|
||||
static uint8_t asn1_invalid_object[] = { ASN1_END, 0 };
|
||||
|
||||
cursor->data = asn1_invalid_object;
|
||||
cursor->len = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start parsing ASN.1 object
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v type Expected type
|
||||
* @v type Expected type, or ASN1_ANY
|
||||
* @ret len Length of object body, or negative error
|
||||
*
|
||||
* The object cursor will be updated to point to the start of the
|
||||
@@ -67,7 +89,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
}
|
||||
|
||||
/* Check the tag byte */
|
||||
if ( *( ( uint8_t * ) cursor->data ) != type ) {
|
||||
if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
|
||||
DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
|
||||
cursor, type, *( ( uint8_t * ) cursor->data ) );
|
||||
return -ENXIO;
|
||||
@@ -110,7 +132,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
* Enter ASN.1 object
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v type Expected type
|
||||
* @v type Expected type, or ASN1_ANY
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The object cursor will be updated to point to the body of the
|
||||
@@ -137,7 +159,7 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
* Skip ASN.1 object if present
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v type Expected type
|
||||
* @v type Expected type, or ASN1_ANY
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The object cursor will be updated to point to the next ASN.1
|
||||
@@ -168,7 +190,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
* Skip ASN.1 object
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v type Expected type
|
||||
* @v type Expected type, or ASN1_ANY
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The object cursor will be updated to point to the next ASN.1
|
||||
@@ -178,10 +200,203 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
int rc;
|
||||
|
||||
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) {
|
||||
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
|
||||
asn1_invalidate_cursor ( cursor );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrink ASN.1 cursor to fit object
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v type Expected type, or ASN1_ANY
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The object cursor will be shrunk to contain only the current ASN.1
|
||||
* object. If any error occurs, the object cursor will be
|
||||
* invalidated.
|
||||
*/
|
||||
int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
struct asn1_cursor temp;
|
||||
const void *end;
|
||||
int len;
|
||||
|
||||
/* Find end of object */
|
||||
memcpy ( &temp, cursor, sizeof ( temp ) );
|
||||
len = asn1_start ( &temp, type );
|
||||
if ( len < 0 ) {
|
||||
asn1_invalidate_cursor ( cursor );
|
||||
return len;
|
||||
}
|
||||
end = ( temp.data + len );
|
||||
|
||||
/* Shrink original cursor to contain only its first object */
|
||||
cursor->len = ( end - cursor->data );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter ASN.1 object of any type
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int asn1_enter_any ( struct asn1_cursor *cursor ) {
|
||||
return asn1_enter ( cursor, ASN1_ANY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip ASN.1 object of any type
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int asn1_skip_any ( struct asn1_cursor *cursor ) {
|
||||
return asn1_skip ( cursor, ASN1_ANY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrink ASN.1 object of any type
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int asn1_shrink_any ( struct asn1_cursor *cursor ) {
|
||||
return asn1_shrink ( cursor, ASN1_ANY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value of ASN.1 boolean
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @ret value Value, or negative error
|
||||
*/
|
||||
int asn1_boolean ( const struct asn1_cursor *cursor ) {
|
||||
struct asn1_cursor contents;
|
||||
const struct asn1_boolean *boolean;
|
||||
|
||||
/* Enter boolean */
|
||||
memcpy ( &contents, cursor, sizeof ( contents ) );
|
||||
asn1_enter ( &contents, ASN1_BOOLEAN );
|
||||
if ( contents.len != sizeof ( *boolean ) )
|
||||
return -EINVAL_ASN1_BOOLEAN;
|
||||
|
||||
/* Extract value */
|
||||
boolean = contents.data;
|
||||
return boolean->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse value of ASN.1 integer
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v value Value to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
|
||||
struct asn1_cursor contents;
|
||||
uint8_t high_byte;
|
||||
int rc;
|
||||
|
||||
/* Enter integer */
|
||||
memcpy ( &contents, cursor, sizeof ( contents ) );
|
||||
if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
|
||||
return rc;
|
||||
if ( contents.len < 1 )
|
||||
return -EINVAL_ASN1_INTEGER;
|
||||
|
||||
/* Initialise value according to sign byte */
|
||||
*value = *( ( int8_t * ) contents.data );
|
||||
contents.data++;
|
||||
contents.len--;
|
||||
|
||||
/* Process value */
|
||||
while ( contents.len ) {
|
||||
high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
|
||||
if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
|
||||
DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
|
||||
return -EINVAL_ASN1_INTEGER;
|
||||
}
|
||||
*value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
|
||||
contents.data++;
|
||||
contents.len--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two ASN.1 objects
|
||||
*
|
||||
* @v cursor1 ASN.1 object cursor
|
||||
* @v cursor2 ASN.1 object cursor
|
||||
* @ret difference Difference as returned by memcmp()
|
||||
*
|
||||
* Note that invalid and empty cursors will compare as equal with each
|
||||
* other.
|
||||
*/
|
||||
int asn1_compare ( const struct asn1_cursor *cursor1,
|
||||
const struct asn1_cursor *cursor2 ) {
|
||||
int difference;
|
||||
|
||||
difference = ( cursor2->len - cursor1->len );
|
||||
return ( difference ? difference :
|
||||
memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify ASN.1 algorithm by OID
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
|
||||
* @ret algorithm Algorithm, or NULL
|
||||
*/
|
||||
static struct asn1_algorithm *
|
||||
asn1_find_algorithm ( const struct asn1_cursor *cursor ) {
|
||||
struct asn1_algorithm *algorithm;
|
||||
|
||||
for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
|
||||
if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse ASN.1 OID-identified algorithm
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @ret algorithm Algorithm, or NULL
|
||||
*/
|
||||
struct asn1_algorithm * asn1_algorithm ( const struct asn1_cursor *cursor ) {
|
||||
struct asn1_cursor contents;
|
||||
struct asn1_algorithm *algorithm;
|
||||
int rc;
|
||||
|
||||
/* Enter signatureAlgorithm */
|
||||
memcpy ( &contents, cursor, sizeof ( contents ) );
|
||||
asn1_enter ( &contents, ASN1_SEQUENCE );
|
||||
|
||||
/* Enter algorithm */
|
||||
if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
|
||||
DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
|
||||
cursor );
|
||||
DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Identify algorithm */
|
||||
algorithm = asn1_find_algorithm ( &contents );
|
||||
if ( ! algorithm ) {
|
||||
DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
|
||||
DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
+85
-106
@@ -1,23 +1,33 @@
|
||||
/*
|
||||
* Copyright(C) 2006 Cameron Rich
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* * 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 the axTLS project nor the names of its 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.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* AES implementation - this is a small code version. There are much faster
|
||||
* versions around but they are much larger in size (i.e. they use large
|
||||
@@ -25,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "os_port.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/* all commented out in skeleton mode */
|
||||
@@ -64,10 +75,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
(f8)^=rot2(f4), \
|
||||
(f8)^rot1(f9))
|
||||
|
||||
/* some macros to do endian independent byte extraction */
|
||||
#define n2l(c,l) l=ntohl(*c); c++
|
||||
#define l2n(l,c) *c++=htonl(l)
|
||||
|
||||
/*
|
||||
* AES S-box
|
||||
*/
|
||||
@@ -154,11 +161,15 @@ static const unsigned char Rcon[30]=
|
||||
0xb3,0x7d,0xfa,0xef,0xc5,0x91,
|
||||
};
|
||||
|
||||
/* ----- static functions ----- */
|
||||
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
|
||||
/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
|
||||
x^8+x^4+x^3+x+1 */
|
||||
static unsigned char AES_xtime(uint32_t x)
|
||||
{
|
||||
return x = (x&0x80) ? (x<<1)^0x1b : x<<1;
|
||||
return (x&0x80) ? (x<<1)^0x1b : x<<1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +258,7 @@ void AES_convert_key(AES_CTX *ctx)
|
||||
k = ctx->ks;
|
||||
k += 4;
|
||||
|
||||
for (i=ctx->rounds*4; i>4; i--)
|
||||
for (i= ctx->rounds*4; i > 4; i--)
|
||||
{
|
||||
w= *k;
|
||||
w = inv_mix_col(w,t1,t2,t3,t4);
|
||||
@@ -255,52 +266,43 @@ void AES_convert_key(AES_CTX *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Encrypt a byte sequence (with a block size 16) using the AES cipher.
|
||||
*/
|
||||
void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
|
||||
{
|
||||
uint32_t tin0, tin1, tin2, tin3;
|
||||
uint32_t tout0, tout1, tout2, tout3;
|
||||
uint32_t tin[4];
|
||||
uint32_t *iv = (uint32_t *)ctx->iv;
|
||||
uint32_t *msg_32 = (uint32_t *)msg;
|
||||
uint32_t *out_32 = (uint32_t *)out;
|
||||
int i;
|
||||
uint32_t tin[4], tout[4], iv[4];
|
||||
|
||||
n2l(iv, tout0);
|
||||
n2l(iv, tout1);
|
||||
n2l(iv, tout2);
|
||||
n2l(iv, tout3);
|
||||
iv -= 4;
|
||||
memcpy(iv, ctx->iv, AES_IV_SIZE);
|
||||
for (i = 0; i < 4; i++)
|
||||
tout[i] = ntohl(iv[i]);
|
||||
|
||||
for (length -= 16; length >= 0; length -= 16)
|
||||
for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
|
||||
{
|
||||
n2l(msg_32, tin0);
|
||||
n2l(msg_32, tin1);
|
||||
n2l(msg_32, tin2);
|
||||
n2l(msg_32, tin3);
|
||||
tin[0] = tin0^tout0;
|
||||
tin[1] = tin1^tout1;
|
||||
tin[2] = tin2^tout2;
|
||||
tin[3] = tin3^tout3;
|
||||
uint32_t msg_32[4];
|
||||
uint32_t out_32[4];
|
||||
memcpy(msg_32, msg, AES_BLOCKSIZE);
|
||||
msg += AES_BLOCKSIZE;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
tin[i] = ntohl(msg_32[i])^tout[i];
|
||||
|
||||
AES_encrypt(ctx, tin);
|
||||
|
||||
tout0 = tin[0];
|
||||
l2n(tout0, out_32);
|
||||
tout1 = tin[1];
|
||||
l2n(tout1, out_32);
|
||||
tout2 = tin[2];
|
||||
l2n(tout2, out_32);
|
||||
tout3 = tin[3];
|
||||
l2n(tout3, out_32);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tout[i] = tin[i];
|
||||
out_32[i] = htonl(tout[i]);
|
||||
}
|
||||
|
||||
memcpy(out, out_32, AES_BLOCKSIZE);
|
||||
out += AES_BLOCKSIZE;
|
||||
}
|
||||
|
||||
l2n(tout0, iv);
|
||||
l2n(tout1, iv);
|
||||
l2n(tout2, iv);
|
||||
l2n(tout3, iv);
|
||||
for (i = 0; i < 4; i++)
|
||||
iv[i] = htonl(tout[i]);
|
||||
memcpy(ctx->iv, iv, AES_IV_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,61 +310,48 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
|
||||
*/
|
||||
void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
|
||||
{
|
||||
uint32_t tin0, tin1, tin2, tin3;
|
||||
uint32_t xor0,xor1,xor2,xor3;
|
||||
uint32_t tout0,tout1,tout2,tout3;
|
||||
uint32_t data[4];
|
||||
uint32_t *iv = (uint32_t *)ctx->iv;
|
||||
uint32_t *msg_32 = (uint32_t *)msg;
|
||||
uint32_t *out_32 = (uint32_t *)out;
|
||||
int i;
|
||||
uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
|
||||
|
||||
n2l(iv ,xor0);
|
||||
n2l(iv, xor1);
|
||||
n2l(iv, xor2);
|
||||
n2l(iv, xor3);
|
||||
iv -= 4;
|
||||
memcpy(iv, ctx->iv, AES_IV_SIZE);
|
||||
for (i = 0; i < 4; i++)
|
||||
xor[i] = ntohl(iv[i]);
|
||||
|
||||
for (length-=16; length >= 0; length -= 16)
|
||||
for (length -= 16; length >= 0; length -= 16)
|
||||
{
|
||||
n2l(msg_32, tin0);
|
||||
n2l(msg_32, tin1);
|
||||
n2l(msg_32, tin2);
|
||||
n2l(msg_32, tin3);
|
||||
uint32_t msg_32[4];
|
||||
uint32_t out_32[4];
|
||||
memcpy(msg_32, msg, AES_BLOCKSIZE);
|
||||
msg += AES_BLOCKSIZE;
|
||||
|
||||
data[0] = tin0;
|
||||
data[1] = tin1;
|
||||
data[2] = tin2;
|
||||
data[3] = tin3;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tin[i] = ntohl(msg_32[i]);
|
||||
data[i] = tin[i];
|
||||
}
|
||||
|
||||
AES_decrypt(ctx, data);
|
||||
|
||||
tout0 = data[0]^xor0;
|
||||
tout1 = data[1]^xor1;
|
||||
tout2 = data[2]^xor2;
|
||||
tout3 = data[3]^xor3;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tout[i] = data[i]^xor[i];
|
||||
xor[i] = tin[i];
|
||||
out_32[i] = htonl(tout[i]);
|
||||
}
|
||||
|
||||
xor0 = tin0;
|
||||
xor1 = tin1;
|
||||
xor2 = tin2;
|
||||
xor3 = tin3;
|
||||
|
||||
l2n(tout0, out_32);
|
||||
l2n(tout1, out_32);
|
||||
l2n(tout2, out_32);
|
||||
l2n(tout3, out_32);
|
||||
memcpy(out, out_32, AES_BLOCKSIZE);
|
||||
out += AES_BLOCKSIZE;
|
||||
}
|
||||
|
||||
l2n(xor0, iv);
|
||||
l2n(xor1, iv);
|
||||
l2n(xor2, iv);
|
||||
l2n(xor3, iv);
|
||||
for (i = 0; i < 4; i++)
|
||||
iv[i] = htonl(xor[i]);
|
||||
memcpy(ctx->iv, iv, AES_IV_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Encrypt a single block (16 bytes) of data
|
||||
*/
|
||||
void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
{
|
||||
/* To make this code smaller, generate the sbox entries on the fly.
|
||||
* This will have a really heavy effect upon performance.
|
||||
@@ -375,9 +364,7 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
|
||||
/* Pre-round key addition */
|
||||
for (row = 0; row < 4; row++)
|
||||
{
|
||||
data[row] ^= *(k++);
|
||||
}
|
||||
|
||||
/* Encrypt one block. */
|
||||
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
|
||||
@@ -395,12 +382,10 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
{
|
||||
tmp1 = a0 ^ a1 ^ a2 ^ a3;
|
||||
old_a0 = a0;
|
||||
|
||||
a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
|
||||
a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
|
||||
a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
|
||||
a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
|
||||
|
||||
}
|
||||
|
||||
tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
|
||||
@@ -409,32 +394,28 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
/* KeyAddition - note that it is vital that this loop is separate from
|
||||
the MixColumn operation, which must be atomic...*/
|
||||
for (row = 0; row < 4; row++)
|
||||
{
|
||||
data[row] = tmp[row] ^ *(k++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a single block (16 bytes) of data
|
||||
*/
|
||||
void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
{
|
||||
uint32_t tmp[4];
|
||||
uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
|
||||
uint32_t a0, a1, a2, a3, row;
|
||||
int curr_rnd;
|
||||
int rounds = ctx->rounds;
|
||||
uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4);
|
||||
const uint32_t *k = ctx->ks + ((rounds+1)*4);
|
||||
|
||||
/* pre-round key addition */
|
||||
for (row=4; row > 0;row--)
|
||||
{
|
||||
data[row-1] ^= *(--k);
|
||||
}
|
||||
|
||||
/* Decrypt one block */
|
||||
for (curr_rnd=0; curr_rnd < rounds; curr_rnd++)
|
||||
for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
|
||||
{
|
||||
/* Perform ByteSub and ShiftRow operations together */
|
||||
for (row = 4; row > 0; row--)
|
||||
@@ -469,9 +450,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
|
||||
}
|
||||
|
||||
for (row = 4; row > 0; row--)
|
||||
{
|
||||
data[row-1] = tmp[row-1] ^ *(--k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+33
-27
@@ -1,44 +1,43 @@
|
||||
/*
|
||||
* Copyright(C) 2006 Cameron Rich
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* * 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 the axTLS project nor the names of its 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.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#ifndef BIGINT_HEADER
|
||||
#define BIGINT_HEADER
|
||||
|
||||
/* enable features based on a 'super-set' capbaility. */
|
||||
#if defined(CONFIG_SSL_FULL_MODE)
|
||||
#define CONFIG_SSL_ENABLE_CLIENT
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#elif defined(CONFIG_SSL_ENABLE_CLIENT)
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#endif
|
||||
#include "crypto.h"
|
||||
|
||||
#include "os_port.h"
|
||||
#include "bigint_impl.h"
|
||||
|
||||
#ifndef CONFIG_BIGINT_CHECK_ON
|
||||
#define check(A) /**< disappears in normal production mode */
|
||||
#endif
|
||||
BI_CTX *bi_initialize(void);
|
||||
void bi_terminate(BI_CTX *ctx);
|
||||
void bi_permanent(bigint *bi);
|
||||
void bi_depermanent(bigint *bi);
|
||||
void bi_clear_cache(BI_CTX *ctx);
|
||||
void bi_free(BI_CTX *ctx, bigint *bi);
|
||||
bigint *bi_copy(bigint *bi);
|
||||
bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
|
||||
@@ -90,4 +89,11 @@ bigint *bi_square(BI_CTX *ctx, bigint *bi);
|
||||
#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
bigint *bi_crt(BI_CTX *ctx, bigint *bi,
|
||||
bigint *dP, bigint *dQ,
|
||||
bigint *p, bigint *q,
|
||||
bigint *qInv);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
/*
|
||||
* Copyright(C) 2006 Cameron Rich
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* * 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 the axTLS project nor the names of its 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 BIGINT_IMPL_HEADER
|
||||
@@ -30,20 +42,39 @@
|
||||
#endif
|
||||
|
||||
/* Architecture specific functions for big ints */
|
||||
#if defined(CONFIG_INTEGER_8BIT)
|
||||
#define COMP_RADIX 256U /**< Max component + 1 */
|
||||
#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */
|
||||
#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */
|
||||
#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */
|
||||
#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */
|
||||
typedef uint8_t comp; /**< A single precision component. */
|
||||
typedef uint16_t long_comp; /**< A double precision component. */
|
||||
typedef int16_t slong_comp; /**< A signed double precision component. */
|
||||
#elif defined(CONFIG_INTEGER_16BIT)
|
||||
#define COMP_RADIX 65536U /**< Max component + 1 */
|
||||
#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */
|
||||
#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */
|
||||
#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */
|
||||
#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */
|
||||
typedef uint16_t comp; /**< A single precision component. */
|
||||
typedef uint32_t long_comp; /**< A double precision component. */
|
||||
typedef int32_t slong_comp; /**< A signed double precision component. */
|
||||
#else /* regular 32 bit */
|
||||
#ifdef WIN32
|
||||
#define COMP_RADIX 4294967296i64
|
||||
#define COMP_BIG_MSB 0x8000000000000000i64
|
||||
#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
|
||||
#else
|
||||
#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
|
||||
#define COMP_BIG_MSB 0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */
|
||||
#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
|
||||
#endif
|
||||
#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
|
||||
#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
|
||||
#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
|
||||
|
||||
typedef uint32_t comp; /**< A single precision component. */
|
||||
typedef uint64_t long_comp; /**< A double precision component. */
|
||||
typedef int64_t slong_comp; /**< A signed double precision component. */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @struct _bigint
|
||||
@@ -97,9 +128,4 @@ typedef struct /**< A big integer "session" context. */
|
||||
|
||||
#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
|
||||
|
||||
#define V1 v->comps[v->size-1] /**< v1 for division */
|
||||
#define V2 v->comps[v->size-2] /**< v2 for division */
|
||||
#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */
|
||||
#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef AXTLS_CONFIG_H
|
||||
#define AXTLS_CONFIG_H
|
||||
|
||||
/**
|
||||
* @file config.h
|
||||
*
|
||||
* Trick the axtls code into building within our build environment.
|
||||
*/
|
||||
|
||||
#define CONFIG_SSL_ENABLE_CLIENT 1
|
||||
#define CONFIG_BIGINT_CLASSICAL 1
|
||||
|
||||
#endif
|
||||
+81
-154
@@ -1,23 +1,33 @@
|
||||
/*
|
||||
* Copyright(C) 2006 Cameron Rich
|
||||
* Copyright (c) 2007, Cameron Rich
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* * 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 the axTLS project nor the names of its 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.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/**
|
||||
* @file crypto.h
|
||||
*/
|
||||
@@ -29,20 +39,40 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "bigint_impl.h"
|
||||
#include "bigint.h"
|
||||
|
||||
#ifndef STDCALL
|
||||
#define STDCALL
|
||||
#endif
|
||||
#ifndef EXP_FUNC
|
||||
#define EXP_FUNC
|
||||
#endif
|
||||
|
||||
|
||||
/* enable features based on a 'super-set' capbaility. */
|
||||
#if defined(CONFIG_SSL_FULL_MODE)
|
||||
#define CONFIG_SSL_ENABLE_CLIENT
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#elif defined(CONFIG_SSL_ENABLE_CLIENT)
|
||||
#define CONFIG_SSL_CERT_VERIFICATION
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* AES declarations
|
||||
**************************************************************************/
|
||||
|
||||
#define AES_MAXROUNDS 14
|
||||
#define AES_BLOCKSIZE 16
|
||||
#define AES_IV_SIZE 16
|
||||
|
||||
typedef struct aes_key_st
|
||||
{
|
||||
uint16_t rounds;
|
||||
uint16_t key_size;
|
||||
uint32_t ks[(AES_MAXROUNDS+1)*8];
|
||||
uint8_t iv[16];
|
||||
uint8_t iv[AES_IV_SIZE];
|
||||
} AES_CTX;
|
||||
|
||||
typedef enum
|
||||
@@ -57,8 +87,6 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
|
||||
uint8_t *out, int length);
|
||||
void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
|
||||
void AES_convert_key(AES_CTX *ctx);
|
||||
void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
|
||||
/**************************************************************************
|
||||
* RC4 declarations
|
||||
@@ -66,7 +94,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x, y, m[256];
|
||||
uint8_t x, y, m[256];
|
||||
} RC4_CTX;
|
||||
|
||||
void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
|
||||
@@ -84,22 +112,38 @@ void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
uint16_t Message_Block_Index; /* Index into message block array */
|
||||
uint8_t Message_Block[64]; /* 512-bit message blocks */
|
||||
uint8_t Message_Block[64]; /* 512-bit message blocks */
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Init(SHA1_CTX *);
|
||||
void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len);
|
||||
void SHA1Final(SHA1_CTX *, uint8_t *digest);
|
||||
void SHA1_Init(SHA1_CTX *);
|
||||
void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
|
||||
void SHA1_Final(uint8_t *digest, SHA1_CTX *);
|
||||
|
||||
/**************************************************************************
|
||||
* MD5 declarations
|
||||
* MD2 declarations
|
||||
**************************************************************************/
|
||||
|
||||
/* MD5 context. */
|
||||
#define MD2_SIZE 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char cksum[16]; /* checksum of the data block */
|
||||
unsigned char state[48]; /* intermediate digest state */
|
||||
unsigned char buffer[16]; /* data block being processed */
|
||||
int left; /* amount of data in buffer */
|
||||
} MD2_CTX;
|
||||
|
||||
EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
|
||||
EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
|
||||
EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
|
||||
|
||||
/**************************************************************************
|
||||
* MD5 declarations
|
||||
**************************************************************************/
|
||||
|
||||
#define MD5_SIZE 16
|
||||
|
||||
@@ -110,9 +154,9 @@ typedef struct
|
||||
uint8_t buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init(MD5_CTX *);
|
||||
void MD5Update(MD5_CTX *, const uint8_t *msg, int len);
|
||||
void MD5Final(MD5_CTX *, uint8_t *digest);
|
||||
EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
|
||||
EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
|
||||
EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
|
||||
|
||||
/**************************************************************************
|
||||
* HMAC declarations
|
||||
@@ -122,19 +166,6 @@ void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
|
||||
void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest);
|
||||
|
||||
/**************************************************************************
|
||||
* RNG declarations
|
||||
**************************************************************************/
|
||||
void RNG_initialize(const uint8_t *seed_buf, int size);
|
||||
void RNG_terminate(void);
|
||||
void get_random(int num_rand_bytes, uint8_t *rand_data);
|
||||
//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
|
||||
|
||||
#include <string.h>
|
||||
static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) {
|
||||
memset ( rand_data, 0x01, num_rand_bytes );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* RSA declarations
|
||||
**************************************************************************/
|
||||
@@ -152,7 +183,6 @@ typedef struct
|
||||
bigint *qInv; /* q^-1 mod p */
|
||||
#endif
|
||||
int num_octets;
|
||||
bigint *sig_m; /* signature modulus */
|
||||
BI_CTX *bi_ctx;
|
||||
} RSA_CTX;
|
||||
|
||||
@@ -175,125 +205,22 @@ void RSA_free(RSA_CTX *ctx);
|
||||
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
|
||||
int is_decryption);
|
||||
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg);
|
||||
#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
|
||||
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
|
||||
bigint *modulus, bigint *pub_exp);
|
||||
bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg);
|
||||
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
|
||||
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
|
||||
uint8_t *out_data, int is_signing);
|
||||
void RSA_print(const RSA_CTX *ctx);
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* ASN1 declarations
|
||||
* RNG declarations
|
||||
**************************************************************************/
|
||||
#define X509_OK 0
|
||||
#define X509_NOT_OK -1
|
||||
#define X509_VFY_ERROR_NO_TRUSTED_CERT -2
|
||||
#define X509_VFY_ERROR_BAD_SIGNATURE -3
|
||||
#define X509_VFY_ERROR_NOT_YET_VALID -4
|
||||
#define X509_VFY_ERROR_EXPIRED -5
|
||||
#define X509_VFY_ERROR_SELF_SIGNED -6
|
||||
#define X509_VFY_ERROR_INVALID_CHAIN -7
|
||||
#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
|
||||
#define X509_INVALID_PRIV_KEY -9
|
||||
|
||||
/*
|
||||
* The Distinguished Name
|
||||
*/
|
||||
#define X509_NUM_DN_TYPES 3
|
||||
#define X509_COMMON_NAME 0
|
||||
#define X509_ORGANIZATION 1
|
||||
#define X509_ORGANIZATIONAL_TYPE 2
|
||||
|
||||
#define ASN1_INTEGER 0x02
|
||||
#define ASN1_BIT_STRING 0x03
|
||||
#define ASN1_OCTET_STRING 0x04
|
||||
#define ASN1_NULL 0x05
|
||||
#define ASN1_OID 0x06
|
||||
#define ASN1_PRINTABLE_STR 0x13
|
||||
#define ASN1_TELETEX_STR 0x14
|
||||
#define ASN1_IA5_STR 0x16
|
||||
#define ASN1_UTC_TIME 0x17
|
||||
#define ASN1_SEQUENCE 0x30
|
||||
#define ASN1_SET 0x31
|
||||
#define ASN1_IMPLICIT_TAG 0x80
|
||||
#define ASN1_EXPLICIT_TAG 0xa0
|
||||
|
||||
#define SALT_SIZE 8
|
||||
|
||||
struct _x509_ctx
|
||||
{
|
||||
char *ca_cert_dn[X509_NUM_DN_TYPES];
|
||||
char *cert_dn[X509_NUM_DN_TYPES];
|
||||
#if defined(_WIN32_WCE)
|
||||
long not_before;
|
||||
long not_after;
|
||||
#else
|
||||
time_t not_before;
|
||||
time_t not_after;
|
||||
#endif
|
||||
uint8_t *signature;
|
||||
uint16_t sig_len;
|
||||
uint8_t sig_type;
|
||||
RSA_CTX *rsa_ctx;
|
||||
bigint *digest;
|
||||
struct _x509_ctx *next;
|
||||
};
|
||||
|
||||
typedef struct _x509_ctx X509_CTX;
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
typedef struct
|
||||
{
|
||||
X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
|
||||
} CA_CERT_CTX;
|
||||
#endif
|
||||
|
||||
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
|
||||
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
|
||||
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
|
||||
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
|
||||
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
|
||||
void x509_free(X509_CTX *x509_ctx);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
|
||||
const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len);
|
||||
#endif
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
|
||||
void x509_display_error(int error);
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* MISC declarations
|
||||
**************************************************************************/
|
||||
|
||||
extern const char * const unsupported_str;
|
||||
|
||||
typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
|
||||
typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key,
|
||||
int key_len, uint8_t *digest);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t *pre_data; /* include the ssl record bytes */
|
||||
uint8_t *data; /* the regular ssl data */
|
||||
int max_len;
|
||||
int index;
|
||||
} BUF_MEM;
|
||||
|
||||
BUF_MEM buf_new(void);
|
||||
void buf_grow(BUF_MEM *bm, int len);
|
||||
void buf_free(BUF_MEM *bm);
|
||||
int get_file(const char *filename, uint8_t **buf);
|
||||
|
||||
#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
|
||||
void print_blob(const char *format, const uint8_t *data, int size, ...);
|
||||
#else
|
||||
#define print_blob(...)
|
||||
#endif
|
||||
EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size);
|
||||
EXP_FUNC void STDCALL RNG_terminate(void);
|
||||
EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
|
||||
void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+32
-39
@@ -1,61 +1,54 @@
|
||||
#ifndef AXTLS_OS_PORT_H
|
||||
#define AXTLS_OS_PORT_H
|
||||
|
||||
/**
|
||||
* @file os_port.h
|
||||
*
|
||||
* Trick the axtls code into building within our build environment.
|
||||
*/
|
||||
|
||||
#ifndef HEADER_OS_PORT_H
|
||||
#define HEADER_OS_PORT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
#define STDCALL
|
||||
#define EXP_FUNC
|
||||
#define TTY_FLUSH()
|
||||
/** All imported axTLS files are licensed using the three-clause BSD licence */
|
||||
FILE_LICENCE ( BSD3 );
|
||||
|
||||
/** We can't actually abort, since we are effectively a kernel... */
|
||||
#define abort() assert ( 0 )
|
||||
|
||||
/** crypto_misc.c has a bad #ifdef */
|
||||
static inline void close ( int fd __unused ) {
|
||||
/* Do nothing */
|
||||
/** rsa.c uses alloca() */
|
||||
#define alloca( size ) __builtin_alloca ( size )
|
||||
|
||||
#include <ipxe/random_nz.h>
|
||||
static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) {
|
||||
/* AXTLS does not check for failures when generating random
|
||||
* data. Rely on the fact that get_random_nz() does not
|
||||
* request prediction resistance (and so cannot introduce new
|
||||
* failures) and therefore any potential failure must already
|
||||
* have been encountered by e.g. tls_generate_random(), which
|
||||
* does check for failures.
|
||||
*/
|
||||
get_random_nz ( rand_data, num_rand_bytes );
|
||||
}
|
||||
|
||||
typedef void FILE;
|
||||
/* Expose AES_encrypt() and AES_decrypt() in aes.o */
|
||||
#define aes 1
|
||||
#if OBJECT
|
||||
|
||||
static inline FILE * fopen ( const char *filename __unused,
|
||||
const char *mode __unused ) {
|
||||
return NULL;
|
||||
struct aes_key_st;
|
||||
|
||||
static void AES_encrypt ( const struct aes_key_st *ctx, uint32_t *data );
|
||||
static void AES_decrypt ( const struct aes_key_st *ctx, uint32_t *data );
|
||||
|
||||
void axtls_aes_encrypt ( void *ctx, uint32_t *data ) {
|
||||
AES_encrypt ( ctx, data );
|
||||
}
|
||||
|
||||
static inline int fseek ( FILE *stream __unused, long offset __unused,
|
||||
int whence __unused ) {
|
||||
return -1;
|
||||
void axtls_aes_decrypt ( void *ctx, uint32_t *data ) {
|
||||
AES_decrypt ( ctx, data );
|
||||
}
|
||||
|
||||
static inline long ftell ( FILE *stream __unused ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline size_t fread ( void *ptr __unused, size_t size __unused,
|
||||
size_t nmemb __unused, FILE *stream __unused ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int fclose ( FILE *stream __unused ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define CONFIG_SSL_CERT_VERIFICATION 1
|
||||
#define CONFIG_SSL_MAX_CERTS 1
|
||||
#define CONFIG_X509_MAX_CA_CERTS 1
|
||||
#define CONFIG_SSL_EXPIRY_TIME 24
|
||||
#define CONFIG_SSL_ENABLE_CLIENT 1
|
||||
#define CONFIG_BIGINT_CLASSICAL 1
|
||||
#endif
|
||||
#undef aes
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
/*
|
||||
* Copyright(C) 2006 Cameron Rich
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements the RSA public encryption algorithm. Uses the bigint library to
|
||||
* perform its calculations.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include "crypto.h"
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi);
|
||||
#endif
|
||||
|
||||
void RSA_priv_key_new(RSA_CTX **ctx,
|
||||
const uint8_t *modulus, int mod_len,
|
||||
const uint8_t *pub_exp, int pub_len,
|
||||
const uint8_t *priv_exp, int priv_len
|
||||
#if CONFIG_BIGINT_CRT
|
||||
, const uint8_t *p, int p_len,
|
||||
const uint8_t *q, int q_len,
|
||||
const uint8_t *dP, int dP_len,
|
||||
const uint8_t *dQ, int dQ_len,
|
||||
const uint8_t *qInv, int qInv_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
RSA_CTX *rsa_ctx;
|
||||
BI_CTX *bi_ctx;
|
||||
RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
|
||||
rsa_ctx = *ctx;
|
||||
bi_ctx = rsa_ctx->bi_ctx;
|
||||
rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
|
||||
bi_permanent(rsa_ctx->d);
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
rsa_ctx->p = bi_import(bi_ctx, p, p_len);
|
||||
rsa_ctx->q = bi_import(bi_ctx, q, q_len);
|
||||
rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
|
||||
rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
|
||||
rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
|
||||
bi_permanent(rsa_ctx->dP);
|
||||
bi_permanent(rsa_ctx->dQ);
|
||||
bi_permanent(rsa_ctx->qInv);
|
||||
bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
|
||||
bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RSA_pub_key_new(RSA_CTX **ctx,
|
||||
const uint8_t *modulus, int mod_len,
|
||||
const uint8_t *pub_exp, int pub_len)
|
||||
{
|
||||
RSA_CTX *rsa_ctx;
|
||||
BI_CTX *bi_ctx = bi_initialize();
|
||||
*ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
|
||||
rsa_ctx = *ctx;
|
||||
rsa_ctx->bi_ctx = bi_ctx;
|
||||
rsa_ctx->num_octets = (mod_len & 0xFFF0);
|
||||
rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
|
||||
bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
|
||||
rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
|
||||
bi_permanent(rsa_ctx->e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free up any RSA context resources.
|
||||
*/
|
||||
void RSA_free(RSA_CTX *rsa_ctx)
|
||||
{
|
||||
BI_CTX *bi_ctx;
|
||||
if (rsa_ctx == NULL) /* deal with ptrs that are null */
|
||||
return;
|
||||
|
||||
bi_ctx = rsa_ctx->bi_ctx;
|
||||
|
||||
bi_depermanent(rsa_ctx->e);
|
||||
bi_free(bi_ctx, rsa_ctx->e);
|
||||
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
|
||||
|
||||
if (rsa_ctx->d)
|
||||
{
|
||||
bi_depermanent(rsa_ctx->d);
|
||||
bi_free(bi_ctx, rsa_ctx->d);
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
bi_depermanent(rsa_ctx->dP);
|
||||
bi_depermanent(rsa_ctx->dQ);
|
||||
bi_depermanent(rsa_ctx->qInv);
|
||||
bi_free(bi_ctx, rsa_ctx->dP);
|
||||
bi_free(bi_ctx, rsa_ctx->dQ);
|
||||
bi_free(bi_ctx, rsa_ctx->qInv);
|
||||
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
|
||||
bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
|
||||
#endif
|
||||
}
|
||||
|
||||
bi_terminate(bi_ctx);
|
||||
free(rsa_ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Use PKCS1.5 for decryption/verification.
|
||||
* @param ctx [in] The context
|
||||
* @param in_data [in] The data to encrypt (must be < modulus size-11)
|
||||
* @param out_data [out] The encrypted data.
|
||||
* @param is_decryption [in] Decryption or verify operation.
|
||||
* @return The number of bytes that were originally encrypted. -1 on error.
|
||||
* @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
|
||||
*/
|
||||
int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data,
|
||||
uint8_t *out_data, int is_decryption)
|
||||
{
|
||||
int byte_size = ctx->num_octets;
|
||||
uint8_t *block;
|
||||
int i, size;
|
||||
bigint *decrypted_bi, *dat_bi;
|
||||
|
||||
memset(out_data, 0, byte_size); /* initialise */
|
||||
|
||||
/* decrypt */
|
||||
dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
decrypted_bi = is_decryption ? /* decrypt or verify? */
|
||||
RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
|
||||
#else /* always a decryption */
|
||||
decrypted_bi = RSA_private(ctx, dat_bi);
|
||||
#endif
|
||||
|
||||
/* convert to a normal block */
|
||||
block = (uint8_t *)malloc(byte_size);
|
||||
bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
|
||||
|
||||
i = 10; /* start at the first possible non-padded byte */
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
|
||||
{
|
||||
while (block[i++] == 0xff && i < byte_size);
|
||||
|
||||
if (block[i-2] != 0xff)
|
||||
i = byte_size; /*ensure size is 0 */
|
||||
}
|
||||
else /* PKCS1.5 encryption padding is random */
|
||||
#endif
|
||||
{
|
||||
while (block[i++] && i < byte_size);
|
||||
}
|
||||
size = byte_size - i;
|
||||
|
||||
/* get only the bit we want */
|
||||
if (size > 0)
|
||||
memcpy(out_data, &block[i], size);
|
||||
|
||||
free(block);
|
||||
return size ? size : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs m = c^d mod n
|
||||
*/
|
||||
bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
|
||||
{
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
return bi_crt(c, bi_msg);
|
||||
#else
|
||||
BI_CTX *ctx = c->bi_ctx;
|
||||
ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
return bi_mod_power(ctx, bi_msg, c->d);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BIGINT_CRT
|
||||
/**
|
||||
* Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
|
||||
* This should really be in bigint.c (and was at one stage), but needs
|
||||
* access to the RSA_CTX context...
|
||||
*/
|
||||
static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi)
|
||||
{
|
||||
BI_CTX *ctx = rsa->bi_ctx;
|
||||
bigint *m1, *m2, *h;
|
||||
|
||||
/* Montgomery has a condition the 0 < x, y < m and these products violate
|
||||
* that condition. So disable Montgomery when using CRT */
|
||||
#if defined(CONFIG_BIGINT_MONTGOMERY)
|
||||
ctx->use_classical = 1;
|
||||
#endif
|
||||
ctx->mod_offset = BIGINT_P_OFFSET;
|
||||
m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP);
|
||||
|
||||
ctx->mod_offset = BIGINT_Q_OFFSET;
|
||||
m2 = bi_mod_power(ctx, bi, rsa->dQ);
|
||||
|
||||
h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL);
|
||||
h = bi_multiply(ctx, h, rsa->qInv);
|
||||
ctx->mod_offset = BIGINT_P_OFFSET;
|
||||
h = bi_residue(ctx, h);
|
||||
#if defined(CONFIG_BIGINT_MONTGOMERY)
|
||||
ctx->use_classical = 0; /* reset for any further operation */
|
||||
#endif
|
||||
return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SSL_FULL_MODE
|
||||
/**
|
||||
* Used for diagnostics.
|
||||
*/
|
||||
void RSA_print(const RSA_CTX *rsa_ctx)
|
||||
{
|
||||
if (rsa_ctx == NULL)
|
||||
return;
|
||||
|
||||
printf("----------------- RSA DEBUG ----------------\n");
|
||||
printf("Size:\t%d\n", rsa_ctx->num_octets);
|
||||
bi_print("Modulus", rsa_ctx->m);
|
||||
bi_print("Public Key", rsa_ctx->e);
|
||||
bi_print("Private Key", rsa_ctx->d);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
/**
|
||||
* Performs c = m^e mod n
|
||||
*/
|
||||
bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
|
||||
{
|
||||
c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
return bi_mod_power(c->bi_ctx, bi_msg, c->e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use PKCS1.5 for encryption/signing.
|
||||
* see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
|
||||
*/
|
||||
int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
|
||||
uint8_t *out_data, int is_signing)
|
||||
{
|
||||
int byte_size = ctx->num_octets;
|
||||
int num_pads_needed = byte_size-in_len-3;
|
||||
bigint *dat_bi, *encrypt_bi;
|
||||
|
||||
/* note: in_len+11 must be > byte_size */
|
||||
out_data[0] = 0; /* ensure encryption block is < modulus */
|
||||
|
||||
if (is_signing)
|
||||
{
|
||||
out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */
|
||||
memset(&out_data[2], 0xff, num_pads_needed);
|
||||
}
|
||||
else /* randomize the encryption padding with non-zero bytes */
|
||||
{
|
||||
out_data[1] = 2;
|
||||
get_random_NZ(num_pads_needed, &out_data[2]);
|
||||
}
|
||||
|
||||
out_data[2+num_pads_needed] = 0;
|
||||
memcpy(&out_data[3+num_pads_needed], in_data, in_len);
|
||||
|
||||
/* now encrypt it */
|
||||
dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
|
||||
encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) :
|
||||
RSA_public(ctx, dat_bi);
|
||||
bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
|
||||
return byte_size;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Take a signature and decrypt it.
|
||||
*/
|
||||
bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
|
||||
bigint *modulus, bigint *pub_exp)
|
||||
{
|
||||
uint8_t *block;
|
||||
int i, size;
|
||||
bigint *decrypted_bi, *dat_bi;
|
||||
bigint *bir = NULL;
|
||||
|
||||
block = (uint8_t *)malloc(sig_len);
|
||||
|
||||
/* decrypt */
|
||||
dat_bi = bi_import(ctx, sig, sig_len);
|
||||
ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
|
||||
/* convert to a normal block */
|
||||
decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
|
||||
|
||||
bi_export(ctx, decrypted_bi, block, sig_len);
|
||||
ctx->mod_offset = BIGINT_M_OFFSET;
|
||||
|
||||
i = 10; /* start at the first possible non-padded byte */
|
||||
while (block[i++] && i < sig_len);
|
||||
size = sig_len - i;
|
||||
|
||||
/* get only the bit we want */
|
||||
if (size > 0)
|
||||
{
|
||||
int len;
|
||||
const uint8_t *sig_ptr = x509_get_signature(&block[i], &len);
|
||||
|
||||
if (sig_ptr)
|
||||
{
|
||||
bir = bi_import(ctx, sig_ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
free(block);
|
||||
return bir;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright(C) 2006 Cameron Rich
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
|
||||
* This code was originally taken from RFC3174
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "crypto.h"
|
||||
|
||||
/*
|
||||
* Define the SHA1 circular left shift macro
|
||||
*/
|
||||
#define SHA1CircularShift(bits,word) \
|
||||
(((word) << (bits)) | ((word) >> (32-(bits))))
|
||||
|
||||
/* ----- static functions ----- */
|
||||
static void SHA1PadMessage(SHA1_CTX *ctx);
|
||||
static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
|
||||
|
||||
/**
|
||||
* Initialize the SHA1 context
|
||||
*/
|
||||
void SHA1Init(SHA1_CTX *ctx)
|
||||
{
|
||||
ctx->Length_Low = 0;
|
||||
ctx->Length_High = 0;
|
||||
ctx->Message_Block_Index = 0;
|
||||
ctx->Intermediate_Hash[0] = 0x67452301;
|
||||
ctx->Intermediate_Hash[1] = 0xEFCDAB89;
|
||||
ctx->Intermediate_Hash[2] = 0x98BADCFE;
|
||||
ctx->Intermediate_Hash[3] = 0x10325476;
|
||||
ctx->Intermediate_Hash[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an array of octets as the next portion of the message.
|
||||
*/
|
||||
void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
|
||||
|
||||
ctx->Length_Low += 8;
|
||||
if (ctx->Length_Low == 0)
|
||||
{
|
||||
ctx->Length_High++;
|
||||
}
|
||||
|
||||
if (ctx->Message_Block_Index == 64)
|
||||
{
|
||||
SHA1ProcessMessageBlock(ctx);
|
||||
}
|
||||
|
||||
msg++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 160-bit message digest into the user's array
|
||||
*/
|
||||
void SHA1Final(SHA1_CTX *ctx, uint8_t *digest)
|
||||
{
|
||||
int i;
|
||||
|
||||
SHA1PadMessage(ctx);
|
||||
memset(ctx->Message_Block, 0, 64);
|
||||
ctx->Length_Low = 0; /* and clear length */
|
||||
ctx->Length_High = 0;
|
||||
|
||||
for (i = 0; i < SHA1_SIZE; i++)
|
||||
{
|
||||
digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next 512 bits of the message stored in the array.
|
||||
*/
|
||||
static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
|
||||
{
|
||||
const uint32_t K[] = { /* Constants defined in SHA-1 */
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; /* Loop counter */
|
||||
uint32_t temp; /* Temporary word value */
|
||||
uint32_t W[80]; /* Word sequence */
|
||||
uint32_t A, B, C, D, E; /* Word buffers */
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for (t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = ctx->Message_Block[t * 4] << 24;
|
||||
W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
|
||||
W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
|
||||
W[t] |= ctx->Message_Block[t * 4 + 3];
|
||||
}
|
||||
|
||||
for (t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = ctx->Intermediate_Hash[0];
|
||||
B = ctx->Intermediate_Hash[1];
|
||||
C = ctx->Intermediate_Hash[2];
|
||||
D = ctx->Intermediate_Hash[3];
|
||||
E = ctx->Intermediate_Hash[4];
|
||||
|
||||
for (t = 0; t < 20; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 20; t < 40; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 40; t < 60; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (t = 60; t < 80; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
ctx->Intermediate_Hash[0] += A;
|
||||
ctx->Intermediate_Hash[1] += B;
|
||||
ctx->Intermediate_Hash[2] += C;
|
||||
ctx->Intermediate_Hash[3] += D;
|
||||
ctx->Intermediate_Hash[4] += E;
|
||||
ctx->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64
|
||||
* bits represent the length of the original message. All bits in
|
||||
* between should be 0. This function will pad the message
|
||||
* according to those rules by filling the Message_Block array
|
||||
* accordingly. It will also call the ProcessMessageBlock function
|
||||
* provided appropriately. When it returns, it can be assumed that
|
||||
* the message digest has been computed.
|
||||
*
|
||||
* @param ctx [in, out] The SHA1 context
|
||||
*/
|
||||
static void SHA1PadMessage(SHA1_CTX *ctx)
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second
|
||||
* block.
|
||||
*/
|
||||
if (ctx->Message_Block_Index > 55)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
|
||||
while(ctx->Message_Block_Index < 64)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
SHA1ProcessMessageBlock(ctx);
|
||||
|
||||
while (ctx->Message_Block_Index < 56)
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
|
||||
while(ctx->Message_Block_Index < 56)
|
||||
{
|
||||
|
||||
ctx->Message_Block[ctx->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
ctx->Message_Block[56] = ctx->Length_High >> 24;
|
||||
ctx->Message_Block[57] = ctx->Length_High >> 16;
|
||||
ctx->Message_Block[58] = ctx->Length_High >> 8;
|
||||
ctx->Message_Block[59] = ctx->Length_High;
|
||||
ctx->Message_Block[60] = ctx->Length_Low >> 24;
|
||||
ctx->Message_Block[61] = ctx->Length_Low >> 16;
|
||||
ctx->Message_Block[62] = ctx->Length_Low >> 8;
|
||||
ctx->Message_Block[63] = ctx->Length_Low;
|
||||
SHA1ProcessMessageBlock(ctx);
|
||||
}
|
||||
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/cbc.h>
|
||||
@@ -119,7 +120,7 @@ static void aes_encrypt ( void *ctx, const void *src, void *dst,
|
||||
assert ( len == AES_BLOCKSIZE );
|
||||
if ( aes_ctx->decrypting )
|
||||
assert ( 0 );
|
||||
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_encrypt );
|
||||
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_encrypt );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +140,7 @@ static void aes_decrypt ( void *ctx, const void *src, void *dst,
|
||||
AES_convert_key ( &aes_ctx->axtls_ctx );
|
||||
aes_ctx->decrypting = 1;
|
||||
}
|
||||
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_decrypt );
|
||||
aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_decrypt );
|
||||
}
|
||||
|
||||
/** Basic AES algorithm */
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#include "crypto/axtls/crypto.h"
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/sha1.h>
|
||||
|
||||
static void sha1_init ( void *ctx ) {
|
||||
SHA1Init ( ctx );
|
||||
}
|
||||
|
||||
static void sha1_update ( void *ctx, const void *data, size_t len ) {
|
||||
SHA1Update ( ctx, data, len );
|
||||
}
|
||||
|
||||
static void sha1_final ( void *ctx, void *out ) {
|
||||
SHA1Final ( ctx, out );
|
||||
}
|
||||
|
||||
struct digest_algorithm sha1_algorithm = {
|
||||
.name = "sha1",
|
||||
.ctxsize = SHA1_CTX_SIZE,
|
||||
.blocksize = 64,
|
||||
.digestsize = SHA1_DIGEST_SIZE,
|
||||
.init = sha1_init,
|
||||
.update = sha1_update,
|
||||
.final = sha1_final,
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/bigint.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Big integer support
|
||||
*/
|
||||
|
||||
/**
|
||||
* Perform modular multiplication of big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v modulus0 Element 0 of big integer modulus
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements in base, modulus, and result
|
||||
* @v tmp Temporary working space
|
||||
*/
|
||||
void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
|
||||
const bigint_element_t *multiplier0,
|
||||
const bigint_element_t *modulus0,
|
||||
bigint_element_t *result0,
|
||||
unsigned int size, void *tmp ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
|
||||
( ( const void * ) modulus0 );
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
struct {
|
||||
bigint_t ( size * 2 ) result;
|
||||
bigint_t ( size * 2 ) modulus;
|
||||
} *temp = tmp;
|
||||
int rotation;
|
||||
int i;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) );
|
||||
|
||||
/* Perform multiplication */
|
||||
bigint_multiply ( multiplicand, multiplier, &temp->result );
|
||||
|
||||
/* Rescale modulus to match result */
|
||||
bigint_grow ( modulus, &temp->modulus );
|
||||
rotation = ( bigint_max_set_bit ( &temp->result ) -
|
||||
bigint_max_set_bit ( &temp->modulus ) );
|
||||
for ( i = 0 ; i < rotation ; i++ )
|
||||
bigint_rol ( &temp->modulus );
|
||||
|
||||
/* Subtract multiples of modulus */
|
||||
for ( i = 0 ; i <= rotation ; i++ ) {
|
||||
if ( bigint_is_geq ( &temp->result, &temp->modulus ) )
|
||||
bigint_subtract ( &temp->modulus, &temp->result );
|
||||
bigint_ror ( &temp->modulus );
|
||||
}
|
||||
|
||||
/* Resize result */
|
||||
bigint_shrink ( &temp->result, result );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( bigint_is_geq ( modulus, result ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform modular exponentiation of big integers
|
||||
*
|
||||
* @v base0 Element 0 of big integer base
|
||||
* @v modulus0 Element 0 of big integer modulus
|
||||
* @v exponent0 Element 0 of big integer exponent
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements in base, modulus, and result
|
||||
* @v exponent_size Number of elements in exponent
|
||||
* @v tmp Temporary working space
|
||||
*/
|
||||
void bigint_mod_exp_raw ( const bigint_element_t *base0,
|
||||
const bigint_element_t *modulus0,
|
||||
const bigint_element_t *exponent0,
|
||||
bigint_element_t *result0,
|
||||
unsigned int size, unsigned int exponent_size,
|
||||
void *tmp ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *base =
|
||||
( ( const void * ) base0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
|
||||
( ( const void * ) modulus0 );
|
||||
const bigint_t ( exponent_size ) __attribute__ (( may_alias ))
|
||||
*exponent = ( ( const void * ) exponent0 );
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus );
|
||||
struct {
|
||||
bigint_t ( size ) base;
|
||||
bigint_t ( exponent_size ) exponent;
|
||||
uint8_t mod_multiply[mod_multiply_len];
|
||||
} *temp = tmp;
|
||||
static const uint8_t start[1] = { 0x01 };
|
||||
|
||||
memcpy ( &temp->base, base, sizeof ( temp->base ) );
|
||||
memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) );
|
||||
bigint_init ( result, start, sizeof ( start ) );
|
||||
|
||||
while ( ! bigint_is_zero ( &temp->exponent ) ) {
|
||||
if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) {
|
||||
bigint_mod_multiply ( result, &temp->base, modulus,
|
||||
result, temp->mod_multiply );
|
||||
}
|
||||
bigint_ror ( &temp->exponent );
|
||||
bigint_mod_multiply ( &temp->base, &temp->base, modulus,
|
||||
&temp->base, temp->mod_multiply );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/dhcp.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/clientcert.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Client certificate store
|
||||
*
|
||||
* Life would in theory be easier if we could use a single file to
|
||||
* hold both the certificate and corresponding private key.
|
||||
* Unfortunately, the only common format which supports this is
|
||||
* PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
|
||||
* codebase. See, for reference and amusement:
|
||||
*
|
||||
* http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sanity checks */
|
||||
#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY)
|
||||
#warning "Attempting to embed certificate with no corresponding private key"
|
||||
#endif
|
||||
#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE)
|
||||
#warning "Attempting to embed private key with no corresponding certificate"
|
||||
#endif
|
||||
|
||||
/* Allow client certificates to be overridden if not explicitly specified */
|
||||
#ifdef CERTIFICATE
|
||||
#define ALLOW_CERT_OVERRIDE 0
|
||||
#else
|
||||
#define ALLOW_CERT_OVERRIDE 1
|
||||
#endif
|
||||
|
||||
/* Raw client certificate data */
|
||||
extern char client_certificate_data[];
|
||||
extern char client_certificate_len[];
|
||||
__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
|
||||
"\nclient_certificate_data:\n\t"
|
||||
#ifdef CERTIFICATE
|
||||
".incbin \"" CERTIFICATE "\"\n\t"
|
||||
#endif /* CERTIFICATE */
|
||||
".size client_certificate_data, ( . - client_certificate_data )\n\t"
|
||||
".equ client_certificate_len, ( . - client_certificate_data )\n\t"
|
||||
".previous\n\t" );
|
||||
|
||||
/* Raw client private key data */
|
||||
extern char client_private_key_data[];
|
||||
extern char client_private_key_len[];
|
||||
__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
|
||||
"\nclient_private_key_data:\n\t"
|
||||
#ifdef PRIVATE_KEY
|
||||
".incbin \"" PRIVATE_KEY "\"\n\t"
|
||||
#endif /* PRIVATE_KEY */
|
||||
".size client_private_key_data, ( . - client_private_key_data )\n\t"
|
||||
".equ client_private_key_len, ( . - client_private_key_data )\n\t"
|
||||
".previous\n\t" );
|
||||
|
||||
/** Client certificate */
|
||||
struct client_certificate client_certificate = {
|
||||
.data = client_certificate_data,
|
||||
.len = ( ( size_t ) client_certificate_len ),
|
||||
};
|
||||
|
||||
/** Client private key */
|
||||
struct client_private_key client_private_key = {
|
||||
.data = client_private_key_data,
|
||||
.len = ( ( size_t ) client_private_key_len ),
|
||||
};
|
||||
|
||||
/** Client certificate setting */
|
||||
static struct setting cert_setting __setting ( SETTING_CRYPTO ) = {
|
||||
.name = "cert",
|
||||
.description = "Client certificate",
|
||||
.tag = DHCP_EB_CERT,
|
||||
.type = &setting_type_hex,
|
||||
};
|
||||
|
||||
/** Client private key setting */
|
||||
static struct setting key_setting __setting ( SETTING_CRYPTO ) = {
|
||||
.name = "key",
|
||||
.description = "Client private key",
|
||||
.tag = DHCP_EB_KEY,
|
||||
.type = &setting_type_hex,
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply client certificate store configuration settings
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int clientcert_apply_settings ( void ) {
|
||||
static void *cert = NULL;
|
||||
static void *key = NULL;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Allow client certificate to be overridden only if
|
||||
* not explicitly specified at build time.
|
||||
*/
|
||||
if ( ALLOW_CERT_OVERRIDE ) {
|
||||
|
||||
/* Restore default client certificate */
|
||||
client_certificate.data = client_certificate_data;
|
||||
client_certificate.len = ( ( size_t ) client_certificate_len );
|
||||
|
||||
/* Fetch new client certificate, if any */
|
||||
free ( cert );
|
||||
len = fetch_setting_copy ( NULL, &cert_setting, &cert );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
|
||||
"client certificate: %s\n", strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
if ( cert ) {
|
||||
client_certificate.data = cert;
|
||||
client_certificate.len = len;
|
||||
}
|
||||
|
||||
/* Restore default client private key */
|
||||
client_private_key.data = client_private_key_data;
|
||||
client_private_key.len = ( ( size_t ) client_private_key_len );
|
||||
|
||||
/* Fetch new client private key, if any */
|
||||
free ( key );
|
||||
len = fetch_setting_copy ( NULL, &key_setting, &key );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
|
||||
"client private key: %s\n", strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
if ( key ) {
|
||||
client_private_key.data = key;
|
||||
client_private_key.len = len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug */
|
||||
if ( have_client_certificate() ) {
|
||||
DBGC ( &client_certificate, "CLIENTCERT using %s "
|
||||
"certificate:\n", ( cert ? "external" : "built-in" ) );
|
||||
DBGC_HDA ( &client_certificate, 0, client_certificate.data,
|
||||
client_certificate.len );
|
||||
DBGC ( &client_certificate, "CLIENTCERT using %s private "
|
||||
"key:\n", ( key ? "external" : "built-in" ) );
|
||||
DBGC_HDA ( &client_certificate, 0, client_private_key.data,
|
||||
client_private_key.len );
|
||||
} else {
|
||||
DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Client certificate store settings applicator */
|
||||
struct settings_applicator clientcert_applicator __settings_applicator = {
|
||||
.apply = clientcert_apply_settings,
|
||||
};
|
||||
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Cryptographic Message Syntax (PKCS #7)
|
||||
*
|
||||
* The format of CMS messages is defined in RFC 5652.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/cms.h>
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EACCES_NON_SIGNING \
|
||||
__einfo_error ( EINFO_EACCES_NON_SIGNING )
|
||||
#define EINFO_EACCES_NON_SIGNING \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x01, "Not a signing certificate" )
|
||||
#define EACCES_NON_CODE_SIGNING \
|
||||
__einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
|
||||
#define EINFO_EACCES_NON_CODE_SIGNING \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
|
||||
#define EACCES_WRONG_NAME \
|
||||
__einfo_error ( EINFO_EACCES_WRONG_NAME )
|
||||
#define EINFO_EACCES_WRONG_NAME \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
|
||||
#define EACCES_NO_SIGNATURES \
|
||||
__einfo_error ( EINFO_EACCES_NO_SIGNATURES )
|
||||
#define EINFO_EACCES_NO_SIGNATURES \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
|
||||
#define EINVAL_DIGEST \
|
||||
__einfo_error ( EINFO_EINVAL_DIGEST )
|
||||
#define EINFO_EINVAL_DIGEST \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" )
|
||||
#define EINVAL_PUBKEY \
|
||||
__einfo_error ( EINFO_EINVAL_PUBKEY )
|
||||
#define EINFO_EINVAL_PUBKEY \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" )
|
||||
#define ENOTSUP_SIGNEDDATA \
|
||||
__einfo_error ( EINFO_ENOTSUP_SIGNEDDATA )
|
||||
#define EINFO_ENOTSUP_SIGNEDDATA \
|
||||
__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" )
|
||||
#define ENOTSUP_DIGEST \
|
||||
__einfo_error ( EINFO_ENOTSUP_DIGEST )
|
||||
#define EINFO_ENOTSUP_DIGEST \
|
||||
__einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported digest algorithm" )
|
||||
#define ENOTSUP_PUBKEY \
|
||||
__einfo_error ( EINFO_ENOTSUP_PUBKEY )
|
||||
#define EINFO_ENOTSUP_PUBKEY \
|
||||
__einfo_uniqify ( EINFO_ENOTSUP, 0x03, \
|
||||
"Unsupported public-key algorithm" )
|
||||
|
||||
/** "pkcs7-signedData" object identifier */
|
||||
static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA };
|
||||
|
||||
/** "pkcs7-signedData" object identifier cursor */
|
||||
static struct asn1_cursor oid_signeddata_cursor =
|
||||
ASN1_OID_CURSOR ( oid_signeddata );
|
||||
|
||||
/**
|
||||
* Parse CMS signature content type
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_content_type ( struct cms_signature *sig,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_cursor cursor;
|
||||
|
||||
/* Enter contentType */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
asn1_enter ( &cursor, ASN1_OID );
|
||||
|
||||
/* Check OID is pkcs7-signedData */
|
||||
if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p does not contain signedData:\n", sig );
|
||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
||||
return -ENOTSUP_SIGNEDDATA;
|
||||
}
|
||||
|
||||
DBGC ( sig, "CMS %p contains signedData\n", sig );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature certificate list
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_certificates ( struct cms_signature *sig,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_cursor cursor;
|
||||
struct x509_certificate *cert;
|
||||
int rc;
|
||||
|
||||
/* Enter certificates */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
|
||||
|
||||
/* Add each certificate */
|
||||
while ( cursor.len ) {
|
||||
|
||||
/* Add certificate to chain */
|
||||
if ( ( rc = x509_append_raw ( sig->certificates, cursor.data,
|
||||
cursor.len ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p could not append certificate: %s\n",
|
||||
sig, strerror ( rc) );
|
||||
DBGC_HDA ( sig, 0, cursor.data, cursor.len );
|
||||
return rc;
|
||||
}
|
||||
cert = x509_last ( sig->certificates );
|
||||
DBGC ( sig, "CMS %p found certificate %s\n",
|
||||
sig, cert->subject.name );
|
||||
|
||||
/* Move to next certificate */
|
||||
asn1_skip_any ( &cursor );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify CMS signature certificate by issuer and serial number
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v issuer Issuer
|
||||
* @v serial Serial number
|
||||
* @ret cert X.509 certificate, or NULL if not found
|
||||
*/
|
||||
static struct x509_certificate *
|
||||
cms_find_issuer_serial ( struct cms_signature *sig,
|
||||
const struct asn1_cursor *issuer,
|
||||
const struct asn1_cursor *serial ) {
|
||||
struct x509_link *link;
|
||||
struct x509_certificate *cert;
|
||||
|
||||
/* Scan through certificate list */
|
||||
list_for_each_entry ( link, &sig->certificates->links, list ) {
|
||||
|
||||
/* Check issuer and serial number */
|
||||
cert = link->cert;
|
||||
if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
|
||||
( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
|
||||
return cert;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature signer identifier
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information to fill in
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_signer_identifier ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_cursor cursor;
|
||||
struct asn1_cursor serial;
|
||||
struct asn1_cursor issuer;
|
||||
struct x509_certificate *cert;
|
||||
int rc;
|
||||
|
||||
/* Enter issuerAndSerialNumber */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Identify issuer */
|
||||
memcpy ( &issuer, &cursor, sizeof ( issuer ) );
|
||||
if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
||||
return rc;
|
||||
}
|
||||
DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
|
||||
DBGC_HDA ( sig, 0, issuer.data, issuer.len );
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Identify serialNumber */
|
||||
memcpy ( &serial, &cursor, sizeof ( serial ) );
|
||||
if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
||||
return rc;
|
||||
}
|
||||
DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
|
||||
DBGC_HDA ( sig, 0, serial.data, serial.len );
|
||||
|
||||
/* Identify certificate */
|
||||
cert = cms_find_issuer_serial ( sig, &issuer, &serial );
|
||||
if ( ! cert ) {
|
||||
DBGC ( sig, "CMS %p/%p could not identify signer's "
|
||||
"certificate\n", sig, info );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Append certificate to chain */
|
||||
if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not append certificate: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Append remaining certificates to chain */
|
||||
if ( ( rc = x509_auto_append ( info->chain,
|
||||
sig->certificates ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not append certificates: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature digest algorithm
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information to fill in
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_digest_algorithm ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_algorithm *algorithm;
|
||||
|
||||
/* Identify algorithm */
|
||||
algorithm = asn1_algorithm ( raw );
|
||||
if ( ! algorithm ) {
|
||||
DBGC ( sig, "CMS %p/%p could not identify digest algorithm:\n",
|
||||
sig, info );
|
||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
||||
return -ENOTSUP_DIGEST;
|
||||
}
|
||||
|
||||
/* Check algorithm is a digest algorithm */
|
||||
if ( ! algorithm->digest ) {
|
||||
DBGC ( sig, "CMS %p/%p algorithm %s is not a digest "
|
||||
"algorithm\n", sig, info, algorithm->name );
|
||||
return -EINVAL_DIGEST;
|
||||
}
|
||||
|
||||
/* Record digest algorithm */
|
||||
info->digest = algorithm->digest;
|
||||
DBGC ( sig, "CMS %p/%p digest algorithm is %s\n",
|
||||
sig, info, algorithm->name );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature algorithm
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information to fill in
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_signature_algorithm ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_algorithm *algorithm;
|
||||
|
||||
/* Identify algorithm */
|
||||
algorithm = asn1_algorithm ( raw );
|
||||
if ( ! algorithm ) {
|
||||
DBGC ( sig, "CMS %p/%p could not identify public-key "
|
||||
"algorithm:\n", sig, info );
|
||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
||||
return -ENOTSUP_PUBKEY;
|
||||
}
|
||||
|
||||
/* Check algorithm is a signature algorithm */
|
||||
if ( ! algorithm->pubkey ) {
|
||||
DBGC ( sig, "CMS %p/%p algorithm %s is not a public-key "
|
||||
"algorithm\n", sig, info, algorithm->name );
|
||||
return -EINVAL_PUBKEY;
|
||||
}
|
||||
|
||||
/* Record signature algorithm */
|
||||
info->pubkey = algorithm->pubkey;
|
||||
DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n",
|
||||
sig, info, algorithm->name );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature value
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information to fill in
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_signature_value ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_cursor cursor;
|
||||
int rc;
|
||||
|
||||
/* Enter signature */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not locate signature:\n",
|
||||
sig, info );
|
||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Record signature */
|
||||
info->signature_len = cursor.len;
|
||||
info->signature = malloc ( info->signature_len );
|
||||
if ( ! info->signature )
|
||||
return -ENOMEM;
|
||||
memcpy ( info->signature, cursor.data, info->signature_len );
|
||||
DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
|
||||
DBGC_HDA ( sig, 0, info->signature, info->signature_len );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature signer information
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information to fill in
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse_signer_info ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_cursor cursor;
|
||||
int rc;
|
||||
|
||||
/* Enter signerInfo */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Skip version */
|
||||
asn1_skip ( &cursor, ASN1_INTEGER );
|
||||
|
||||
/* Parse sid */
|
||||
if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 )
|
||||
return rc;
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Parse digestAlgorithm */
|
||||
if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 )
|
||||
return rc;
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Skip signedAttrs, if present */
|
||||
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
|
||||
|
||||
/* Parse signatureAlgorithm */
|
||||
if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0)
|
||||
return rc;
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Parse signature */
|
||||
if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CMS signature from ASN.1 data
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_parse ( struct cms_signature *sig,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct asn1_cursor cursor;
|
||||
struct cms_signer_info *info;
|
||||
int rc;
|
||||
|
||||
/* Enter contentInfo */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Parse contentType */
|
||||
|
||||
if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
|
||||
return rc;
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Enter content */
|
||||
asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
|
||||
|
||||
/* Enter signedData */
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Skip version */
|
||||
asn1_skip ( &cursor, ASN1_INTEGER );
|
||||
|
||||
/* Skip digestAlgorithms */
|
||||
asn1_skip ( &cursor, ASN1_SET );
|
||||
|
||||
/* Skip encapContentInfo */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Parse certificates */
|
||||
if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 )
|
||||
return rc;
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Skip crls, if present */
|
||||
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
|
||||
|
||||
/* Enter signerInfos */
|
||||
asn1_enter ( &cursor, ASN1_SET );
|
||||
|
||||
/* Add each signerInfo. Errors are handled by ensuring that
|
||||
* cms_put() will always be able to free any allocated memory.
|
||||
*/
|
||||
while ( cursor.len ) {
|
||||
|
||||
/* Allocate signer information block */
|
||||
info = zalloc ( sizeof ( *info ) );
|
||||
if ( ! info )
|
||||
return -ENOMEM;
|
||||
list_add ( &info->list, &sig->info );
|
||||
|
||||
/* Allocate certificate chain */
|
||||
info->chain = x509_alloc_chain();
|
||||
if ( ! info->chain )
|
||||
return -ENOMEM;
|
||||
|
||||
/* Parse signerInfo */
|
||||
if ( ( rc = cms_parse_signer_info ( sig, info,
|
||||
&cursor ) ) != 0 )
|
||||
return rc;
|
||||
asn1_skip_any ( &cursor );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free CMS signature
|
||||
*
|
||||
* @v refcnt Reference count
|
||||
*/
|
||||
static void cms_free ( struct refcnt *refcnt ) {
|
||||
struct cms_signature *sig =
|
||||
container_of ( refcnt, struct cms_signature, refcnt );
|
||||
struct cms_signer_info *info;
|
||||
struct cms_signer_info *tmp;
|
||||
|
||||
list_for_each_entry_safe ( info, tmp, &sig->info, list ) {
|
||||
list_del ( &info->list );
|
||||
x509_chain_put ( info->chain );
|
||||
free ( info->signature );
|
||||
free ( info );
|
||||
}
|
||||
x509_chain_put ( sig->certificates );
|
||||
free ( sig );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create CMS signature
|
||||
*
|
||||
* @v data Raw signature data
|
||||
* @v len Length of raw data
|
||||
* @ret sig CMS signature
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* On success, the caller holds a reference to the CMS signature, and
|
||||
* is responsible for ultimately calling cms_put().
|
||||
*/
|
||||
int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
|
||||
struct asn1_cursor cursor;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise signature */
|
||||
*sig = zalloc ( sizeof ( **sig ) );
|
||||
if ( ! *sig ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
ref_init ( &(*sig)->refcnt, cms_free );
|
||||
INIT_LIST_HEAD ( &(*sig)->info );
|
||||
|
||||
/* Allocate certificate list */
|
||||
(*sig)->certificates = x509_alloc_chain();
|
||||
if ( ! (*sig)->certificates ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_chain;
|
||||
}
|
||||
|
||||
/* Initialise cursor */
|
||||
cursor.data = data;
|
||||
cursor.len = len;
|
||||
asn1_shrink_any ( &cursor );
|
||||
|
||||
/* Parse signature */
|
||||
if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 )
|
||||
goto err_parse;
|
||||
|
||||
return 0;
|
||||
|
||||
err_parse:
|
||||
err_alloc_chain:
|
||||
cms_put ( *sig );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate digest of CMS-signed data
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information
|
||||
* @v data Signed data
|
||||
* @v len Length of signed data
|
||||
* @v out Digest output
|
||||
*/
|
||||
static void cms_digest ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
userptr_t data, size_t len, void *out ) {
|
||||
struct digest_algorithm *digest = info->digest;
|
||||
uint8_t ctx[ digest->ctxsize ];
|
||||
uint8_t block[ digest->blocksize ];
|
||||
size_t offset = 0;
|
||||
size_t frag_len;
|
||||
|
||||
/* Initialise digest */
|
||||
digest_init ( digest, ctx );
|
||||
|
||||
/* Process data one block at a time */
|
||||
while ( len ) {
|
||||
frag_len = len;
|
||||
if ( frag_len > sizeof ( block ) )
|
||||
frag_len = sizeof ( block );
|
||||
copy_from_user ( block, data, offset, frag_len );
|
||||
digest_update ( digest, ctx, block, frag_len );
|
||||
offset += frag_len;
|
||||
len -= frag_len;
|
||||
}
|
||||
|
||||
/* Finalise digest */
|
||||
digest_final ( digest, ctx, out );
|
||||
|
||||
DBGC ( sig, "CMS %p/%p digest value:\n", sig, info );
|
||||
DBGC_HDA ( sig, 0, out, digest->digestsize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify digest of CMS-signed data
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information
|
||||
* @v cert Corresponding certificate
|
||||
* @v data Signed data
|
||||
* @v len Length of signed data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_verify_digest ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
struct x509_certificate *cert,
|
||||
userptr_t data, size_t len ) {
|
||||
struct digest_algorithm *digest = info->digest;
|
||||
struct pubkey_algorithm *pubkey = info->pubkey;
|
||||
struct x509_public_key *public_key = &cert->subject.public_key;
|
||||
uint8_t digest_out[ digest->digestsize ];
|
||||
uint8_t ctx[ pubkey->ctxsize ];
|
||||
int rc;
|
||||
|
||||
/* Generate digest */
|
||||
cms_digest ( sig, info, data, len, digest_out );
|
||||
|
||||
/* Initialise public-key algorithm */
|
||||
if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
|
||||
public_key->raw.len ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
/* Verify digest */
|
||||
if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
|
||||
info->signature,
|
||||
info->signature_len ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p signature verification failed: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
goto err_verify;
|
||||
}
|
||||
|
||||
err_verify:
|
||||
pubkey_final ( pubkey, ctx );
|
||||
err_init:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify CMS signature signer information
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v info Signer information
|
||||
* @v data Signed data
|
||||
* @v len Length of signed data
|
||||
* @v time Time at which to validate certificates
|
||||
* @v root Root certificate store, or NULL to use default
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cms_verify_signer_info ( struct cms_signature *sig,
|
||||
struct cms_signer_info *info,
|
||||
userptr_t data, size_t len,
|
||||
time_t time, struct x509_root *root ) {
|
||||
struct x509_certificate *cert;
|
||||
int rc;
|
||||
|
||||
/* Validate certificate chain */
|
||||
if ( ( rc = x509_validate_chain ( info->chain, time, root ) ) != 0 ) {
|
||||
DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
|
||||
sig, info, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Extract code-signing certificate */
|
||||
cert = x509_first ( info->chain );
|
||||
assert ( cert != NULL );
|
||||
|
||||
/* Check that certificate can create digital signatures */
|
||||
if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
|
||||
DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
|
||||
sig, info );
|
||||
return -EACCES_NON_SIGNING;
|
||||
}
|
||||
|
||||
/* Check that certificate can sign code */
|
||||
if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
|
||||
DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
|
||||
sig, info );
|
||||
return -EACCES_NON_CODE_SIGNING;
|
||||
}
|
||||
|
||||
/* Verify digest */
|
||||
if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify CMS signature
|
||||
*
|
||||
* @v sig CMS signature
|
||||
* @v data Signed data
|
||||
* @v len Length of signed data
|
||||
* @v name Required common name, or NULL to check all signatures
|
||||
* @v time Time at which to validate certificates
|
||||
* @v root Root certificate store, or NULL to use default
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
|
||||
const char *name, time_t time, struct x509_root *root ) {
|
||||
struct cms_signer_info *info;
|
||||
struct x509_certificate *cert;
|
||||
int count = 0;
|
||||
int rc;
|
||||
|
||||
/* Verify using all signerInfos */
|
||||
list_for_each_entry ( info, &sig->info, list ) {
|
||||
cert = x509_first ( info->chain );
|
||||
if ( name && ( ( cert->subject.name == NULL ) ||
|
||||
( strcmp ( cert->subject.name, name ) != 0 ) ) )
|
||||
continue;
|
||||
if ( ( rc = cms_verify_signer_info ( sig, info, data, len,
|
||||
time, root ) ) != 0 )
|
||||
return rc;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Check that we have verified at least one signature */
|
||||
if ( count == 0 ) {
|
||||
if ( name ) {
|
||||
DBGC ( sig, "CMS %p had no signatures matching name "
|
||||
"%s\n", sig, name );
|
||||
return -EACCES_WRONG_NAME;
|
||||
} else {
|
||||
DBGC ( sig, "CMS %p had no signatures\n", sig );
|
||||
return -EACCES_NO_SIGNATURES;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Cryptographically strong random number generator
|
||||
*
|
||||
* Currently the cryptographic part is not implemented, and this just
|
||||
* uses random().
|
||||
*/
|
||||
|
||||
#include <ipxe/crypto.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Get cryptographically strong random bytes
|
||||
*
|
||||
* @v buf Buffer in which to store random bytes
|
||||
* @v len Number of random bytes to generate
|
||||
*
|
||||
* @b WARNING: This function is currently underimplemented, and does
|
||||
* not give numbers any stronger than random()!
|
||||
*/
|
||||
void get_random_bytes ( void *buf, size_t len )
|
||||
{
|
||||
u8 *bufp = buf;
|
||||
|
||||
/*
|
||||
* Somewhat arbitrarily, choose the 0x00FF0000-masked byte
|
||||
* returned by random() as having good entropy. PRNGs often
|
||||
* don't provide good entropy in lower bits, and the top byte
|
||||
* might show a pattern because of sign issues.
|
||||
*/
|
||||
|
||||
while ( len-- ) {
|
||||
*bufp++ = ( random() >> 16 ) & 0xFF;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,56 @@ struct cipher_algorithm cipher_null = {
|
||||
.decrypt = cipher_null_decrypt,
|
||||
};
|
||||
|
||||
static int pubkey_null_init ( void *ctx __unused, const void *key __unused,
|
||||
size_t key_len __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t pubkey_null_max_len ( void *ctx __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pubkey_null_encrypt ( void *ctx __unused,
|
||||
const void *plaintext __unused,
|
||||
size_t plaintext_len __unused,
|
||||
void *ciphertext __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pubkey_null_decrypt ( void *ctx __unused,
|
||||
const void *ciphertext __unused,
|
||||
size_t ciphertext_len __unused,
|
||||
void *plaintext __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pubkey_null_sign ( void *ctx __unused,
|
||||
struct digest_algorithm *digest __unused,
|
||||
const void *value __unused,
|
||||
void *signature __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pubkey_null_verify ( void *ctx __unused,
|
||||
struct digest_algorithm *digest __unused,
|
||||
const void *value __unused,
|
||||
const void *signature __unused ,
|
||||
size_t signature_len __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pubkey_null_final ( void *ctx __unused ) {
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
struct pubkey_algorithm pubkey_null = {
|
||||
.name = "null",
|
||||
.ctxsize = 0,
|
||||
.init = pubkey_null_init,
|
||||
.max_len = pubkey_null_max_len,
|
||||
.encrypt = pubkey_null_encrypt,
|
||||
.decrypt = pubkey_null_decrypt,
|
||||
.sign = pubkey_null_sign,
|
||||
.verify = pubkey_null_verify,
|
||||
.final = pubkey_null_final,
|
||||
};
|
||||
|
||||
+18
-8
@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/entropy.h>
|
||||
@@ -62,7 +63,7 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal,
|
||||
unsigned int entropy_bits = ( ( 3 * DRBG_SECURITY_STRENGTH + 1 ) / 2 );
|
||||
size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
|
||||
size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
|
||||
uint8_t data[ entropy_bufsize ( entropy_bits, min_len, max_len ) ];
|
||||
uint8_t data[max_len];
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
@@ -127,8 +128,8 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal,
|
||||
state, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
assert ( len >= min_len );
|
||||
assert ( len <= sizeof ( data ) );
|
||||
assert ( len >= ( int ) min_len );
|
||||
assert ( len <= ( int ) sizeof ( data ) );
|
||||
|
||||
/* 9. initial_working_state = Instantiate_algorithm (
|
||||
* entropy_input, nonce, personalization_string ).
|
||||
@@ -150,6 +151,7 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal,
|
||||
* in-situ.)
|
||||
*/
|
||||
state->reseed_required = 0;
|
||||
state->valid = 1;
|
||||
|
||||
/* 12. Return SUCCESS and state_handle. */
|
||||
return 0;
|
||||
@@ -173,7 +175,7 @@ int drbg_reseed ( struct drbg_state *state, const void *additional,
|
||||
unsigned int entropy_bits = DRBG_SECURITY_STRENGTH;
|
||||
size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
|
||||
size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
|
||||
uint8_t data[ entropy_bufsize ( entropy_bits, min_len, max_len ) ];
|
||||
uint8_t data[max_len];
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
@@ -186,9 +188,13 @@ int drbg_reseed ( struct drbg_state *state, const void *additional,
|
||||
* If state_handle indicates an invalid or empty internal
|
||||
* state, return an ERROR_FLAG.
|
||||
*
|
||||
* (Nothing to do since the memory holding the internal state
|
||||
* was passed in by the caller.)
|
||||
* (Almost nothing to do since the memory holding the internal
|
||||
* state was passed in by the caller.)
|
||||
*/
|
||||
if ( ! state->valid ) {
|
||||
DBGC ( state, "DRBG %p not valid\n", state );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* 2. If prediction_resistance_request is set, and
|
||||
* prediction_resistance_flag is not set, then return an
|
||||
@@ -272,9 +278,13 @@ int drbg_generate ( struct drbg_state *state, const void *additional,
|
||||
* for the instantiation. If state_handle indicates an
|
||||
* invalid or empty internal state, then return an ERROR_FLAG.
|
||||
*
|
||||
* (Nothing to do since the memory holding the internal state
|
||||
* was passed in by the caller.)
|
||||
* (Almost nothing to do since the memory holding the internal
|
||||
* state was passed in by the caller.)
|
||||
*/
|
||||
if ( ! state->valid ) {
|
||||
DBGC ( state, "DRBG %p not valid\n", state );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* 2. If requested_number_of_bits >
|
||||
* max_number_of_bits_per_request, then return an
|
||||
|
||||
+443
-13
@@ -22,27 +22,457 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*
|
||||
* Entropy source
|
||||
*
|
||||
* This algorithm is designed to comply with ANS X9.82 Part 4 (April
|
||||
* 2011 Draft) Section 13.3. This standard is unfortunately not
|
||||
* freely available.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/hash_df.h>
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EPIPE_REPETITION_COUNT_TEST \
|
||||
__einfo_error ( EINFO_EPIPE_REPETITION_COUNT_TEST )
|
||||
#define EINFO_EPIPE_REPETITION_COUNT_TEST \
|
||||
__einfo_uniqify ( EINFO_EPIPE, 0x01, "Repetition count test failed" )
|
||||
#define EPIPE_ADAPTIVE_PROPORTION_TEST \
|
||||
__einfo_error ( EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST )
|
||||
#define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \
|
||||
__einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
|
||||
|
||||
/**
|
||||
* Obtain entropy input
|
||||
* Calculate cutoff value for the repetition count test
|
||||
*
|
||||
* @v entropy_bits Minimum amount of entropy, in bits
|
||||
* @v data Data buffer
|
||||
* @v min_len Minimum length of entropy input, in bytes
|
||||
* @v max_len Maximum length of entropy input, in bytes
|
||||
* @ret len Length of entropy input, in bytes
|
||||
* @ret cutoff Cutoff value
|
||||
*
|
||||
* This is the cutoff value for the Repetition Count Test defined in
|
||||
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
|
||||
*/
|
||||
int get_entropy_input ( unsigned int entropy_bits, void *data, size_t min_len,
|
||||
size_t max_len ) {
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
repetition_count_cutoff ( void ) {
|
||||
double max_repetitions;
|
||||
unsigned int cutoff;
|
||||
|
||||
/* Placeholder to allow remainder of RBG code to be tested */
|
||||
( void ) entropy_bits;
|
||||
( void ) min_len;
|
||||
memset ( data, 0x01, max_len );
|
||||
/* The cutoff formula for the repetition test is:
|
||||
*
|
||||
* C = ( 1 + ( -log2(W) / H_min ) )
|
||||
*
|
||||
* where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
|
||||
* 2011 Draft) Section 8.5.2.1.3.1).
|
||||
*/
|
||||
max_repetitions = ( 1 + ( 30 / min_entropy_per_sample() ) );
|
||||
|
||||
return max_len;
|
||||
/* Round up to a whole number of repetitions. We don't have
|
||||
* the ceil() function available, so do the rounding by hand.
|
||||
*/
|
||||
cutoff = max_repetitions;
|
||||
if ( cutoff < max_repetitions )
|
||||
cutoff++;
|
||||
linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
|
||||
|
||||
/* Floating-point operations are not allowed in iPXE since we
|
||||
* never set up a suitable environment. Abort the build
|
||||
* unless the calculated number of repetitions is a
|
||||
* compile-time constant.
|
||||
*/
|
||||
linker_assert ( __builtin_constant_p ( cutoff ),
|
||||
repetition_count_cutoff_not_constant );
|
||||
|
||||
return cutoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform repetition count test
|
||||
*
|
||||
* @v sample Noise sample
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This is the Repetition Count Test defined in ANS X9.82 Part 2
|
||||
* (October 2011 Draft) Section 8.5.2.1.2.
|
||||
*/
|
||||
static int repetition_count_test ( noise_sample_t sample ) {
|
||||
static noise_sample_t most_recent_sample;
|
||||
static unsigned int repetition_count = 0;
|
||||
|
||||
/* A = the most recently seen sample value
|
||||
* B = the number of times that value A has been seen in a row
|
||||
* C = the cutoff value above which the repetition test should fail
|
||||
*/
|
||||
|
||||
/* 1. For each new sample processed:
|
||||
*
|
||||
* (Note that the test for "repetition_count > 0" ensures that
|
||||
* the initial value of most_recent_sample is treated as being
|
||||
* undefined.)
|
||||
*/
|
||||
if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) {
|
||||
|
||||
/* a) If the new sample = A, then B is incremented by one. */
|
||||
repetition_count++;
|
||||
|
||||
/* i. If B >= C, then an error condition is raised
|
||||
* due to a failure of the test
|
||||
*/
|
||||
if ( repetition_count >= repetition_count_cutoff() )
|
||||
return -EPIPE_REPETITION_COUNT_TEST;
|
||||
|
||||
} else {
|
||||
|
||||
/* b) Else:
|
||||
* i. A = new sample
|
||||
*/
|
||||
most_recent_sample = sample;
|
||||
|
||||
/* ii. B = 1 */
|
||||
repetition_count = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Window size for the adaptive proportion test
|
||||
*
|
||||
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
|
||||
* five possible window sizes: 16, 64, 256, 4096 and 65536.
|
||||
*
|
||||
* We expect to generate relatively few (<256) entropy samples during
|
||||
* a typical iPXE run; the use of a large window size would mean that
|
||||
* the test would never complete a single cycle. We use a window size
|
||||
* of 64, which is the smallest window size that permits values of
|
||||
* H_min down to one bit per sample.
|
||||
*/
|
||||
#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
|
||||
|
||||
/**
|
||||
* Combine adaptive proportion test window size and min-entropy
|
||||
*
|
||||
* @v n N (window size)
|
||||
* @v h H (min-entropy)
|
||||
* @ret n_h (N,H) combined value
|
||||
*/
|
||||
#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
|
||||
|
||||
/**
|
||||
* Define a row of the adaptive proportion cutoff table
|
||||
*
|
||||
* @v h H (min-entropy)
|
||||
* @v c16 Cutoff for N=16
|
||||
* @v c64 Cutoff for N=64
|
||||
* @v c256 Cutoff for N=256
|
||||
* @v c4096 Cutoff for N=4096
|
||||
* @v c65536 Cutoff for N=65536
|
||||
*/
|
||||
#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \
|
||||
case APC_N_H ( 16, h ) : return c16; \
|
||||
case APC_N_H ( 64, h ) : return c64; \
|
||||
case APC_N_H ( 256, h ) : return c256; \
|
||||
case APC_N_H ( 4096, h ) : return c4096; \
|
||||
case APC_N_H ( 65536, h ) : return c65536;
|
||||
|
||||
/** Value used to represent "N/A" in adaptive proportion cutoff table */
|
||||
#define APC_NA 0
|
||||
|
||||
/**
|
||||
* Look up value in adaptive proportion test cutoff table
|
||||
*
|
||||
* @v n N (window size)
|
||||
* @v h H (min-entropy)
|
||||
* @ret cutoff Cutoff
|
||||
*
|
||||
* This is the table of cutoff values defined in ANS X9.82 Part 2
|
||||
* (October 2011 Draft) Section 8.5.2.1.3.1.2.
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
|
||||
switch ( APC_N_H ( n, h ) ) {
|
||||
APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 );
|
||||
APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 );
|
||||
APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 );
|
||||
APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 );
|
||||
APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 );
|
||||
APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 );
|
||||
APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 );
|
||||
APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 );
|
||||
APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 );
|
||||
APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 );
|
||||
APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 );
|
||||
APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 );
|
||||
APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 );
|
||||
APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 );
|
||||
APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 );
|
||||
APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 );
|
||||
APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 );
|
||||
APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 );
|
||||
APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 );
|
||||
APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 );
|
||||
default:
|
||||
return APC_NA;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate cutoff value for the adaptive proportion test
|
||||
*
|
||||
* @ret cutoff Cutoff value
|
||||
*
|
||||
* This is the cutoff value for the Adaptive Proportion Test defined
|
||||
* in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
adaptive_proportion_cutoff ( void ) {
|
||||
unsigned int h;
|
||||
unsigned int n;
|
||||
unsigned int cutoff;
|
||||
|
||||
/* Look up cutoff value in cutoff table */
|
||||
n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
|
||||
h = min_entropy_per_sample();
|
||||
cutoff = adaptive_proportion_cutoff_lookup ( n, h );
|
||||
|
||||
/* Fail unless cutoff value is a build-time constant */
|
||||
linker_assert ( __builtin_constant_p ( cutoff ),
|
||||
adaptive_proportion_cutoff_not_constant );
|
||||
|
||||
/* Fail if cutoff value is N/A */
|
||||
linker_assert ( ( cutoff != APC_NA ),
|
||||
adaptive_proportion_cutoff_not_applicable );
|
||||
|
||||
return cutoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform adaptive proportion test
|
||||
*
|
||||
* @v sample Noise sample
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This is the Adaptive Proportion Test for the Most Common Value
|
||||
* defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
|
||||
*/
|
||||
static int adaptive_proportion_test ( noise_sample_t sample ) {
|
||||
static noise_sample_t current_counted_sample;
|
||||
static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
|
||||
static unsigned int repetition_count;
|
||||
|
||||
/* A = the sample value currently being counted
|
||||
* B = the number of samples examined in this run of the test so far
|
||||
* N = the total number of samples that must be observed in
|
||||
* one run of the test, also known as the "window size" of
|
||||
* the test
|
||||
* B = the current number of times that S (sic) has been seen
|
||||
* in the W (sic) samples examined so far
|
||||
* C = the cutoff value above which the repetition test should fail
|
||||
* W = the probability of a false positive: 2^-30
|
||||
*/
|
||||
|
||||
/* 1. The entropy source draws the current sample from the
|
||||
* noise source.
|
||||
*
|
||||
* (Nothing to do; we already have the current sample.)
|
||||
*/
|
||||
|
||||
/* 2. If S = N, then a new run of the test begins: */
|
||||
if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
|
||||
|
||||
/* a. A = the current sample */
|
||||
current_counted_sample = sample;
|
||||
|
||||
/* b. S = 0 */
|
||||
sample_count = 0;
|
||||
|
||||
/* c. B = 0 */
|
||||
repetition_count = 0;
|
||||
|
||||
} else {
|
||||
|
||||
/* Else: (the test is already running)
|
||||
* a. S = S + 1
|
||||
*/
|
||||
sample_count++;
|
||||
|
||||
/* b. If A = the current sample, then: */
|
||||
if ( sample == current_counted_sample ) {
|
||||
|
||||
/* i. B = B + 1 */
|
||||
repetition_count++;
|
||||
|
||||
/* ii. If S (sic) > C then raise an error
|
||||
* condition, because the test has
|
||||
* detected a failure
|
||||
*/
|
||||
if ( repetition_count > adaptive_proportion_cutoff() )
|
||||
return -EPIPE_ADAPTIVE_PROPORTION_TEST;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entropy sample
|
||||
*
|
||||
* @ret entropy Entropy sample
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This is the GetEntropy function defined in ANS X9.82 Part 2
|
||||
* (October 2011 Draft) Section 6.5.1.
|
||||
*/
|
||||
static int get_entropy ( entropy_sample_t *entropy ) {
|
||||
static int rc = 0;
|
||||
noise_sample_t noise;
|
||||
|
||||
/* Any failure is permanent */
|
||||
if ( rc != 0 )
|
||||
return rc;
|
||||
|
||||
/* Get noise sample */
|
||||
if ( ( rc = get_noise ( &noise ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Perform Repetition Count Test and Adaptive Proportion Test
|
||||
* as mandated by ANS X9.82 Part 2 (October 2011 Draft)
|
||||
* Section 8.5.2.1.1.
|
||||
*/
|
||||
if ( ( rc = repetition_count_test ( noise ) ) != 0 )
|
||||
return rc;
|
||||
if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* We do not use any optional conditioning component */
|
||||
*entropy = noise;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of samples required for startup tests
|
||||
*
|
||||
* @ret num_samples Number of samples required
|
||||
*
|
||||
* ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
|
||||
* that at least one full cycle of the continuous tests must be
|
||||
* performed at start-up.
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
startup_test_count ( void ) {
|
||||
unsigned int num_samples;
|
||||
|
||||
/* At least max(N,C) samples shall be generated by the noise
|
||||
* source for start-up testing.
|
||||
*/
|
||||
num_samples = repetition_count_cutoff();
|
||||
if ( num_samples < adaptive_proportion_cutoff() )
|
||||
num_samples = adaptive_proportion_cutoff();
|
||||
linker_assert ( __builtin_constant_p ( num_samples ),
|
||||
startup_test_count_not_constant );
|
||||
|
||||
return num_samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create next nonce value
|
||||
*
|
||||
* @ret nonce Nonce
|
||||
*
|
||||
* This is the MakeNextNonce function defined in ANS X9.82 Part 4
|
||||
* (April 2011 Draft) Section 13.3.4.2.
|
||||
*/
|
||||
static uint32_t make_next_nonce ( void ) {
|
||||
static uint32_t nonce;
|
||||
|
||||
/* The simplest implementation of a nonce uses a large counter */
|
||||
nonce++;
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain entropy input temporary buffer
|
||||
*
|
||||
* @v num_samples Number of entropy samples
|
||||
* @v tmp Temporary buffer
|
||||
* @v tmp_len Length of temporary buffer
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This is (part of) the implementation of the Get_entropy_input
|
||||
* function (using an entropy source as the source of entropy input
|
||||
* and condensing each entropy source output after each GetEntropy
|
||||
* call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
|
||||
* 13.3.4.2.
|
||||
*
|
||||
* To minimise code size, the number of samples required is calculated
|
||||
* at compilation time.
|
||||
*/
|
||||
int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
|
||||
size_t tmp_len ) {
|
||||
static unsigned int startup_tested = 0;
|
||||
struct {
|
||||
uint32_t nonce;
|
||||
entropy_sample_t sample;
|
||||
} __attribute__ (( packed )) data;;
|
||||
uint8_t df_buf[tmp_len];
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Enable entropy gathering */
|
||||
if ( ( rc = entropy_enable() ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Perform mandatory startup tests, if not yet performed */
|
||||
for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
|
||||
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
|
||||
goto err_get_entropy;
|
||||
}
|
||||
|
||||
/* 3. entropy_total = 0
|
||||
*
|
||||
* (Nothing to do; the number of entropy samples required has
|
||||
* already been precalculated.)
|
||||
*/
|
||||
|
||||
/* 4. tmp = a fixed n-bit value, such as 0^n */
|
||||
memset ( tmp, 0, tmp_len );
|
||||
|
||||
/* 5. While ( entropy_total < min_entropy ) */
|
||||
while ( num_samples-- ) {
|
||||
/* 5.1. ( status, entropy_bitstring, assessed_entropy )
|
||||
* = GetEntropy()
|
||||
* 5.2. If status indicates an error, return ( status, Null )
|
||||
*/
|
||||
if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
|
||||
goto err_get_entropy;
|
||||
|
||||
/* 5.3. nonce = MakeNextNonce() */
|
||||
data.nonce = make_next_nonce();
|
||||
|
||||
/* 5.4. tmp = tmp XOR
|
||||
* df ( ( nonce || entropy_bitstring ), n )
|
||||
*/
|
||||
hash_df ( &entropy_hash_df_algorithm, &data, sizeof ( data ),
|
||||
df_buf, sizeof ( df_buf ) );
|
||||
for ( i = 0 ; i < tmp_len ; i++ )
|
||||
tmp[i] ^= df_buf[i];
|
||||
|
||||
/* 5.5. entropy_total = entropy_total + assessed_entropy
|
||||
*
|
||||
* (Nothing to do; the number of entropy samples
|
||||
* required has already been precalculated.)
|
||||
*/
|
||||
}
|
||||
|
||||
/* Disable entropy gathering */
|
||||
entropy_disable();
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_entropy:
|
||||
entropy_disable();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Hash-based derivation function (Hash_df)
|
||||
*
|
||||
* This algorithm is designed to comply with ANS X9.82 Part 3-2007
|
||||
* Section 10.5.2. This standard is not freely available, but most of
|
||||
* the text appears to be shared with NIST SP 800-90, which can be
|
||||
* downloaded from
|
||||
*
|
||||
* http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
|
||||
*
|
||||
* Where possible, references are given to both documents. In the
|
||||
* case of any disagreement, ANS X9.82 takes priority over NIST SP
|
||||
* 800-90. (In particular, note that some algorithms that are
|
||||
* Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/hash_df.h>
|
||||
|
||||
/**
|
||||
* Distribute entropy throughout a buffer
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v input Input data
|
||||
* @v input_len Length of input data, in bytes
|
||||
* @v output Output buffer
|
||||
* @v output_len Length of output buffer, in bytes
|
||||
*
|
||||
* This is the Hash_df function defined in ANS X9.82 Part 3-2007
|
||||
* Section 10.5.2 (NIST SP 800-90 Section 10.4.1).
|
||||
*
|
||||
* The number of bits requested is implicit in the length of the
|
||||
* output buffer. Requests must be for an integral number of bytes.
|
||||
*
|
||||
* The output buffer is filled incrementally with each iteration of
|
||||
* the central loop, rather than constructing an overall "temp" and
|
||||
* then taking the leftmost(no_of_bits_to_return) bits.
|
||||
*
|
||||
* There is no way for the Hash_df function to fail. The returned
|
||||
* status SUCCESS is implicit.
|
||||
*/
|
||||
void hash_df ( struct digest_algorithm *hash, const void *input,
|
||||
size_t input_len, void *output, size_t output_len ) {
|
||||
uint8_t context[hash->ctxsize];
|
||||
uint8_t digest[hash->digestsize];
|
||||
size_t frag_len;
|
||||
struct {
|
||||
uint8_t pad[3];
|
||||
uint8_t counter;
|
||||
uint32_t no_of_bits_to_return;
|
||||
} __attribute__ (( packed )) prefix;
|
||||
void *temp;
|
||||
size_t remaining;
|
||||
|
||||
DBGC ( &hash_df, "HASH_DF input:\n" );
|
||||
DBGC_HDA ( &hash_df, 0, input, input_len );
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( input != NULL );
|
||||
assert ( output != NULL );
|
||||
|
||||
/* 1. temp = the Null string
|
||||
* 2. len = ceil ( no_of_bits_to_return / outlen )
|
||||
*
|
||||
* (Nothing to do. We fill the output buffer incrementally,
|
||||
* rather than constructing the complete "temp" in-memory.
|
||||
* "len" is implicit in the number of iterations required to
|
||||
* fill the output buffer, and so is not calculated
|
||||
* explicitly.)
|
||||
*/
|
||||
|
||||
/* 3. counter = an 8-bit binary value representing the integer "1" */
|
||||
prefix.counter = 1;
|
||||
|
||||
/* 4. For i = 1 to len do */
|
||||
for ( temp = output, remaining = output_len ; remaining > 0 ; ) {
|
||||
|
||||
/* Comment: in step 5.1 (sic), no_of_bits_to_return is
|
||||
* used as a 32-bit string.
|
||||
*
|
||||
* 4.1 temp = temp || Hash ( counter || no_of_bits_to_return
|
||||
* || input_string )
|
||||
*/
|
||||
prefix.no_of_bits_to_return = htonl ( output_len * 8 );
|
||||
digest_init ( hash, context );
|
||||
digest_update ( hash, context, &prefix.counter,
|
||||
( sizeof ( prefix ) -
|
||||
offsetof ( typeof ( prefix ), counter ) ) );
|
||||
digest_update ( hash, context, input, input_len );
|
||||
digest_final ( hash, context, digest );
|
||||
|
||||
/* 4.2 counter = counter + 1 */
|
||||
prefix.counter++;
|
||||
|
||||
/* 5. requested_bits = Leftmost ( no_of_bits_to_return )
|
||||
* of temp
|
||||
*
|
||||
* (We fill the output buffer incrementally.)
|
||||
*/
|
||||
frag_len = sizeof ( digest );
|
||||
if ( frag_len > remaining )
|
||||
frag_len = remaining;
|
||||
memcpy ( temp, digest, frag_len );
|
||||
temp += frag_len;
|
||||
remaining -= frag_len;
|
||||
}
|
||||
|
||||
/* 6. Return SUCCESS and requested_bits */
|
||||
DBGC ( &hash_df, "HASH_DF output:\n" );
|
||||
DBGC_HDA ( &hash_df, 0, output, output_len );
|
||||
return;
|
||||
}
|
||||
+73
-57
@@ -36,7 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/hmac.h>
|
||||
#include <ipxe/hmac_drbg.h>
|
||||
@@ -44,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
/**
|
||||
* Update the HMAC_DRBG key
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v state HMAC_DRBG internal state
|
||||
* @v data Provided data
|
||||
* @v len Length of provided data
|
||||
@@ -55,40 +58,40 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*
|
||||
* as used by hmac_drbg_update()
|
||||
*/
|
||||
static void hmac_drbg_update_key ( struct hmac_drbg_state *state,
|
||||
static void hmac_drbg_update_key ( struct digest_algorithm *hash,
|
||||
struct hmac_drbg_state *state,
|
||||
const void *data, size_t len,
|
||||
const uint8_t single ) {
|
||||
uint8_t context[HMAC_DRBG_CTX_SIZE];
|
||||
size_t key_len = sizeof ( state->key );
|
||||
uint8_t context[ hash->ctxsize ];
|
||||
size_t out_len = hash->digestsize;
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p provided data :\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
|
||||
DBGC_HDA ( state, 0, data, len );
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( hash != NULL );
|
||||
assert ( state != NULL );
|
||||
assert ( ( data != NULL ) || ( len == 0 ) );
|
||||
assert ( ( single == 0x00 ) || ( single == 0x01 ) );
|
||||
|
||||
/* K = HMAC ( K, V || single || provided_data ) */
|
||||
hmac_init ( &hmac_drbg_algorithm, context, state->key, &key_len );
|
||||
assert ( key_len == sizeof ( state->key ) );
|
||||
hmac_update ( &hmac_drbg_algorithm, context,
|
||||
state->value, sizeof ( state->value ) );
|
||||
hmac_update ( &hmac_drbg_algorithm, context,
|
||||
&single, sizeof ( single ) );
|
||||
hmac_update ( &hmac_drbg_algorithm, context, data, len );
|
||||
hmac_final ( &hmac_drbg_algorithm, context, state->key, &key_len,
|
||||
state->key );
|
||||
assert ( key_len == sizeof ( state->key ) );
|
||||
hmac_init ( hash, context, state->key, &out_len );
|
||||
assert ( out_len == hash->digestsize );
|
||||
hmac_update ( hash, context, state->value, out_len );
|
||||
hmac_update ( hash, context, &single, sizeof ( single ) );
|
||||
hmac_update ( hash, context, data, len );
|
||||
hmac_final ( hash, context, state->key, &out_len, state->key );
|
||||
assert ( out_len == hash->digestsize );
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p K = HMAC ( K, V || %#02x || "
|
||||
"provided_data ) :\n", state, single );
|
||||
DBGC_HDA ( state, 0, state->key, sizeof ( state->key ) );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
|
||||
"provided_data ) :\n", hash->name, state, single );
|
||||
DBGC_HDA ( state, 0, state->key, out_len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the HMAC_DRBG value
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v state HMAC_DRBG internal state
|
||||
* @v data Provided data
|
||||
* @v len Length of provided data
|
||||
@@ -100,29 +103,31 @@ static void hmac_drbg_update_key ( struct hmac_drbg_state *state,
|
||||
*
|
||||
* as used by hmac_drbg_update() and hmac_drbg_generate()
|
||||
*/
|
||||
static void hmac_drbg_update_value ( struct hmac_drbg_state *state ) {
|
||||
uint8_t context[HMAC_DRBG_CTX_SIZE];
|
||||
size_t key_len = sizeof ( state->key );
|
||||
static void hmac_drbg_update_value ( struct digest_algorithm *hash,
|
||||
struct hmac_drbg_state *state ) {
|
||||
uint8_t context[ hash->ctxsize ];
|
||||
size_t out_len = hash->digestsize;
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( hash != NULL );
|
||||
assert ( state != NULL );
|
||||
|
||||
/* V = HMAC ( K, V ) */
|
||||
hmac_init ( &hmac_drbg_algorithm, context, state->key, &key_len );
|
||||
assert ( key_len == sizeof ( state->key ) );
|
||||
hmac_update ( &hmac_drbg_algorithm, context,
|
||||
state->value, sizeof ( state->value ) );
|
||||
hmac_final ( &hmac_drbg_algorithm, context, state->key, &key_len,
|
||||
state->value );
|
||||
assert ( key_len == sizeof ( state->key ) );
|
||||
hmac_init ( hash, context, state->key, &out_len );
|
||||
assert ( out_len == hash->digestsize );
|
||||
hmac_update ( hash, context, state->value, out_len );
|
||||
hmac_final ( hash, context, state->key, &out_len, state->value );
|
||||
assert ( out_len == hash->digestsize );
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p V = HMAC ( K, V ) :\n", state );
|
||||
DBGC_HDA ( state, 0, state->value, sizeof ( state->value ) );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
|
||||
hash->name, state );
|
||||
DBGC_HDA ( state, 0, state->value, out_len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update HMAC_DRBG internal state
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v state HMAC_DRBG internal state
|
||||
* @v data Provided data
|
||||
* @v len Length of provided data
|
||||
@@ -133,30 +138,32 @@ static void hmac_drbg_update_value ( struct hmac_drbg_state *state ) {
|
||||
* The key and value are updated in-place within the HMAC_DRBG
|
||||
* internal state.
|
||||
*/
|
||||
static void hmac_drbg_update ( struct hmac_drbg_state *state,
|
||||
static void hmac_drbg_update ( struct digest_algorithm *hash,
|
||||
struct hmac_drbg_state *state,
|
||||
const void *data, size_t len ) {
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p update\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p update\n", hash->name, state );
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( hash != NULL );
|
||||
assert ( state != NULL );
|
||||
assert ( ( data != NULL ) || ( len == 0 ) );
|
||||
|
||||
/* 1. K = HMAC ( K, V || 0x00 || provided_data ) */
|
||||
hmac_drbg_update_key ( state, data, len, 0x00 );
|
||||
hmac_drbg_update_key ( hash, state, data, len, 0x00 );
|
||||
|
||||
/* 2. V = HMAC ( K, V ) */
|
||||
hmac_drbg_update_value ( state );
|
||||
hmac_drbg_update_value ( hash, state );
|
||||
|
||||
/* 3. If ( provided_data = Null ), then return K and V */
|
||||
if ( ! len )
|
||||
return;
|
||||
|
||||
/* 4. K = HMAC ( K, V || 0x01 || provided_data ) */
|
||||
hmac_drbg_update_key ( state, data, len, 0x01 );
|
||||
hmac_drbg_update_key ( hash, state, data, len, 0x01 );
|
||||
|
||||
/* 5. V = HMAC ( K, V ) */
|
||||
hmac_drbg_update_value ( state );
|
||||
hmac_drbg_update_value ( hash, state );
|
||||
|
||||
/* 6. Return K and V */
|
||||
}
|
||||
@@ -164,6 +171,7 @@ static void hmac_drbg_update ( struct hmac_drbg_state *state,
|
||||
/**
|
||||
* Instantiate HMAC_DRBG
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v state HMAC_DRBG internal state to be initialised
|
||||
* @v entropy Entropy input
|
||||
* @v entropy_len Length of entropy input
|
||||
@@ -182,17 +190,18 @@ static void hmac_drbg_update ( struct hmac_drbg_state *state,
|
||||
* The key, value and reseed counter are updated in-place within the
|
||||
* HMAC_DRBG internal state.
|
||||
*/
|
||||
void hmac_drbg_instantiate ( struct hmac_drbg_state *state,
|
||||
void hmac_drbg_instantiate ( struct digest_algorithm *hash,
|
||||
struct hmac_drbg_state *state,
|
||||
const void *entropy, size_t entropy_len,
|
||||
const void *personal, size_t personal_len ){
|
||||
size_t out_len = hash->digestsize;
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p instantiate\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state );
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( hash != NULL );
|
||||
assert ( state != NULL );
|
||||
assert ( entropy != NULL );
|
||||
assert ( ( 8 * entropy_len ) >=
|
||||
( 3 * HMAC_DRBG_SECURITY_STRENGTH / 2 ) );
|
||||
assert ( ( personal != NULL ) || ( personal_len == 0 ) );
|
||||
|
||||
/* 1. seed_material = entropy_input || nonce ||
|
||||
@@ -200,23 +209,24 @@ void hmac_drbg_instantiate ( struct hmac_drbg_state *state,
|
||||
*/
|
||||
|
||||
/* 2. Key = 0x00 00..00 */
|
||||
memset ( state->key, 0x00, sizeof ( state->key ) );
|
||||
memset ( state->key, 0x00, out_len );
|
||||
|
||||
/* 3. V = 0x01 01...01 */
|
||||
memset ( state->value, 0x01, sizeof ( state->value ) );
|
||||
memset ( state->value, 0x01, out_len );
|
||||
|
||||
/* 4. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V )
|
||||
* 5. reseed_counter = 1
|
||||
* 6. Return V, Key and reseed_counter as the
|
||||
* initial_working_state
|
||||
*/
|
||||
hmac_drbg_reseed ( state, entropy, entropy_len,
|
||||
hmac_drbg_reseed ( hash, state, entropy, entropy_len,
|
||||
personal, personal_len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseed HMAC_DRBG
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v state HMAC_DRBG internal state
|
||||
* @v entropy Entropy input
|
||||
* @v entropy_len Length of entropy input
|
||||
@@ -229,27 +239,29 @@ void hmac_drbg_instantiate ( struct hmac_drbg_state *state,
|
||||
* The key, value and reseed counter are updated in-place within the
|
||||
* HMAC_DRBG internal state.
|
||||
*/
|
||||
void hmac_drbg_reseed ( struct hmac_drbg_state *state,
|
||||
void hmac_drbg_reseed ( struct digest_algorithm *hash,
|
||||
struct hmac_drbg_state *state,
|
||||
const void *entropy, size_t entropy_len,
|
||||
const void *additional, size_t additional_len ) {
|
||||
uint8_t seed_material[ entropy_len + additional_len ];
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p (re)seed\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state );
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( hash != NULL );
|
||||
assert ( state != NULL );
|
||||
assert ( entropy != NULL );
|
||||
assert ( ( 8 * entropy_len ) >= HMAC_DRBG_SECURITY_STRENGTH );
|
||||
assert ( ( additional != NULL ) || ( additional_len == 0 ) );
|
||||
|
||||
/* 1. seed_material = entropy_input || additional_input */
|
||||
memcpy ( seed_material, entropy, entropy_len );
|
||||
memcpy ( ( seed_material + entropy_len ), additional, additional_len );
|
||||
DBGC ( state, "HMAC_DRBG %p seed material :\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state );
|
||||
DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) );
|
||||
|
||||
/* 2. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */
|
||||
hmac_drbg_update ( state, seed_material, sizeof ( seed_material ) );
|
||||
hmac_drbg_update ( hash, state, seed_material,
|
||||
sizeof ( seed_material ) );
|
||||
|
||||
/* 3. reseed_counter = 1 */
|
||||
state->reseed_counter = 1;
|
||||
@@ -260,6 +272,7 @@ void hmac_drbg_reseed ( struct hmac_drbg_state *state,
|
||||
/**
|
||||
* Generate pseudorandom bits using HMAC_DRBG
|
||||
*
|
||||
* @v hash Underlying hash algorithm
|
||||
* @v state HMAC_DRBG internal state
|
||||
* @v additional Additional input
|
||||
* @v additional_len Length of additional input
|
||||
@@ -277,16 +290,19 @@ void hmac_drbg_reseed ( struct hmac_drbg_state *state,
|
||||
*
|
||||
* Note that the only permitted error is "reseed required".
|
||||
*/
|
||||
int hmac_drbg_generate ( struct hmac_drbg_state *state,
|
||||
int hmac_drbg_generate ( struct digest_algorithm *hash,
|
||||
struct hmac_drbg_state *state,
|
||||
const void *additional, size_t additional_len,
|
||||
void *data, size_t len ) {
|
||||
size_t out_len = hash->digestsize;
|
||||
void *orig_data = data;
|
||||
size_t orig_len = len;
|
||||
size_t frag_len;
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p generate\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state );
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( hash != NULL );
|
||||
assert ( state != NULL );
|
||||
assert ( data != NULL );
|
||||
assert ( ( additional != NULL ) || ( additional_len == 0 ) );
|
||||
@@ -295,8 +311,8 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state,
|
||||
* indication that a reseed is required
|
||||
*/
|
||||
if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) {
|
||||
DBGC ( state, "HMAC_DRBG %p reseed interval exceeded\n",
|
||||
state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n",
|
||||
hash->name, state );
|
||||
return -ESTALE;
|
||||
}
|
||||
|
||||
@@ -304,7 +320,7 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state,
|
||||
* ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V )
|
||||
*/
|
||||
if ( additional_len )
|
||||
hmac_drbg_update ( state, additional, additional_len );
|
||||
hmac_drbg_update ( hash, state, additional, additional_len );
|
||||
|
||||
/* 3. temp = Null
|
||||
* 4. While ( len ( temp ) < requested_number_of_bits ) do:
|
||||
@@ -312,27 +328,27 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state,
|
||||
while ( len ) {
|
||||
|
||||
/* 4.1 V = HMAC ( Key, V ) */
|
||||
hmac_drbg_update_value ( state );
|
||||
hmac_drbg_update_value ( hash, state );
|
||||
|
||||
/* 4.2. temp = temp || V
|
||||
* 5. returned_bits = Leftmost requested_number_of_bits
|
||||
* of temp
|
||||
*/
|
||||
frag_len = len;
|
||||
if ( frag_len > sizeof ( state->value ) )
|
||||
frag_len = sizeof ( state->value );
|
||||
if ( frag_len > out_len )
|
||||
frag_len = out_len;
|
||||
memcpy ( data, state->value, frag_len );
|
||||
data += frag_len;
|
||||
len -= frag_len;
|
||||
}
|
||||
|
||||
/* 6. ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */
|
||||
hmac_drbg_update ( state, additional, additional_len );
|
||||
hmac_drbg_update ( hash, state, additional, additional_len );
|
||||
|
||||
/* 7. reseed_counter = reseed_counter + 1 */
|
||||
state->reseed_counter++;
|
||||
|
||||
DBGC ( state, "HMAC_DRBG %p generated :\n", state );
|
||||
DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state );
|
||||
DBGC_HDA ( state, 0, orig_data, orig_len );
|
||||
|
||||
/* 8. Return SUCCESS, returned_bits, and the new values of
|
||||
|
||||
+257
-194
@@ -1,234 +1,297 @@
|
||||
/*
|
||||
* Cryptographic API.
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* MD5 Message Digest Algorithm (RFC1321).
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* Derived from cryptoapi implementation, originally based on the
|
||||
* public domain implementation written by Colin Plumb in 1993.
|
||||
*
|
||||
* Reduced object size by around 50% compared to the original Linux
|
||||
* version for use in Etherboot by Michael Brown.
|
||||
*
|
||||
* Copyright (c) Cryptoapi developers.
|
||||
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
|
||||
* Copyright (c) 2006 Michael Brown <mbrown@fensystems.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* MD5 algorithm
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <byteswap.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/rotate.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/md5.h>
|
||||
|
||||
/** MD5 variables */
|
||||
struct md5_variables {
|
||||
/* This layout matches that of struct md5_digest_data,
|
||||
* allowing for efficient endianness-conversion,
|
||||
*/
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
uint32_t w[16];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** MD5 constants */
|
||||
static const uint32_t k[64] = {
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
|
||||
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
|
||||
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
|
||||
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
|
||||
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
|
||||
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
||||
};
|
||||
|
||||
/** MD5 shift amounts */
|
||||
static const uint8_t r[64] = {
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
|
||||
};
|
||||
|
||||
/**
|
||||
* f(b,c,d) for steps 0 to 15
|
||||
*
|
||||
* @v v MD5 variables
|
||||
* @ret f f(b,c,d)
|
||||
*/
|
||||
static uint32_t md5_f_0_15 ( struct md5_variables *v ) {
|
||||
return ( v->d ^ ( v->b & ( v->c ^ v->d ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* f(b,c,d) for steps 16 to 31
|
||||
*
|
||||
* @v v MD5 variables
|
||||
* @ret f f(b,c,d)
|
||||
*/
|
||||
static uint32_t md5_f_16_31 ( struct md5_variables *v ) {
|
||||
return ( v->c ^ ( v->d & ( v->b ^ v->c ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* f(b,c,d) for steps 32 to 47
|
||||
*
|
||||
* @v v MD5 variables
|
||||
* @ret f f(b,c,d)
|
||||
*/
|
||||
static uint32_t md5_f_32_47 ( struct md5_variables *v ) {
|
||||
return ( v->b ^ v->c ^ v->d );
|
||||
}
|
||||
|
||||
/**
|
||||
* f(b,c,d) for steps 48 to 63
|
||||
*
|
||||
* @v v MD5 variables
|
||||
* @ret f f(b,c,d)
|
||||
*/
|
||||
static uint32_t md5_f_48_63 ( struct md5_variables *v ) {
|
||||
return ( v->c ^ ( v->b | (~v->d) ) );
|
||||
}
|
||||
|
||||
/** An MD5 step function */
|
||||
struct md5_step {
|
||||
u32 ( * f ) ( u32 b, u32 c, u32 d );
|
||||
u8 coefficient;
|
||||
u8 constant;
|
||||
/**
|
||||
* Calculate f(b,c,d)
|
||||
*
|
||||
* @v v MD5 variables
|
||||
* @ret f f(b,c,d)
|
||||
*/
|
||||
uint32_t ( * f ) ( struct md5_variables *v );
|
||||
/** Coefficient of i in g=ni+m */
|
||||
uint8_t coefficient;
|
||||
/** Constant term in g=ni+m */
|
||||
uint8_t constant;
|
||||
};
|
||||
|
||||
static u32 f1(u32 b, u32 c, u32 d)
|
||||
{
|
||||
return ( d ^ ( b & ( c ^ d ) ) );
|
||||
}
|
||||
|
||||
static u32 f2(u32 b, u32 c, u32 d)
|
||||
{
|
||||
return ( c ^ ( d & ( b ^ c ) ) );
|
||||
}
|
||||
|
||||
static u32 f3(u32 b, u32 c, u32 d)
|
||||
{
|
||||
return ( b ^ c ^ d );
|
||||
}
|
||||
|
||||
static u32 f4(u32 b, u32 c, u32 d)
|
||||
{
|
||||
return ( c ^ ( b | ~d ) );
|
||||
}
|
||||
|
||||
/** MD5 steps */
|
||||
static struct md5_step md5_steps[4] = {
|
||||
{
|
||||
.f = f1,
|
||||
.coefficient = 1,
|
||||
.constant = 0,
|
||||
},
|
||||
{
|
||||
.f = f2,
|
||||
.coefficient = 5,
|
||||
.constant = 1,
|
||||
},
|
||||
{
|
||||
.f = f3,
|
||||
.coefficient = 3,
|
||||
.constant = 5,
|
||||
},
|
||||
{
|
||||
.f = f4,
|
||||
.coefficient = 7,
|
||||
.constant = 0,
|
||||
}
|
||||
/** 0 to 15 */
|
||||
{ .f = md5_f_0_15, .coefficient = 1, .constant = 0 },
|
||||
/** 16 to 31 */
|
||||
{ .f = md5_f_16_31, .coefficient = 5, .constant = 1 },
|
||||
/** 32 to 47 */
|
||||
{ .f = md5_f_32_47, .coefficient = 3, .constant = 5 },
|
||||
/** 48 to 63 */
|
||||
{ .f = md5_f_48_63, .coefficient = 7, .constant = 0 },
|
||||
};
|
||||
|
||||
static const u8 r[64] = {
|
||||
7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
|
||||
5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
|
||||
4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
|
||||
6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
|
||||
};
|
||||
/**
|
||||
* Initialise MD5 algorithm
|
||||
*
|
||||
* @v ctx MD5 context
|
||||
*/
|
||||
static void md5_init ( void *ctx ) {
|
||||
struct md5_context *context = ctx;
|
||||
|
||||
static const u32 k[64] = {
|
||||
0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
|
||||
0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
|
||||
0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
|
||||
0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
|
||||
0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
|
||||
0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
|
||||
0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
|
||||
0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
|
||||
0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
|
||||
0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
|
||||
0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
|
||||
0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
|
||||
0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
|
||||
0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
|
||||
0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
|
||||
0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
|
||||
};
|
||||
context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 );
|
||||
context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 );
|
||||
context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe );
|
||||
context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 );
|
||||
context->len = 0;
|
||||
}
|
||||
|
||||
static void md5_transform(u32 *hash, const u32 *in)
|
||||
{
|
||||
u32 a, b, c, d, f, g, temp;
|
||||
int i;
|
||||
/**
|
||||
* Calculate MD5 digest of accumulated data
|
||||
*
|
||||
* @v context MD5 context
|
||||
*/
|
||||
static void md5_digest ( struct md5_context *context ) {
|
||||
union {
|
||||
union md5_digest_data_dwords ddd;
|
||||
struct md5_variables v;
|
||||
} u;
|
||||
uint32_t *a = &u.v.a;
|
||||
uint32_t *b = &u.v.b;
|
||||
uint32_t *c = &u.v.c;
|
||||
uint32_t *d = &u.v.d;
|
||||
uint32_t *w = u.v.w;
|
||||
uint32_t f;
|
||||
uint32_t g;
|
||||
uint32_t temp;
|
||||
struct md5_step *step;
|
||||
unsigned int i;
|
||||
|
||||
a = hash[0];
|
||||
b = hash[1];
|
||||
c = hash[2];
|
||||
d = hash[3];
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout );
|
||||
|
||||
DBGC ( context, "MD5 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
DBGC_HDA ( context, context->len, &context->ddd.dd.data,
|
||||
sizeof ( context->ddd.dd.data ) );
|
||||
|
||||
/* Convert h[0..3] to host-endian, and initialise a, b, c, d,
|
||||
* and w[0..15]
|
||||
*/
|
||||
for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
|
||||
sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
|
||||
le32_to_cpus ( &context->ddd.dword[i] );
|
||||
u.ddd.dword[i] = context->ddd.dword[i];
|
||||
}
|
||||
|
||||
/* Main loop */
|
||||
for ( i = 0 ; i < 64 ; i++ ) {
|
||||
step = &md5_steps[i >> 4];
|
||||
f = step->f ( b, c, d );
|
||||
g = ( ( i * step->coefficient + step->constant ) & 0xf );
|
||||
temp = d;
|
||||
d = c;
|
||||
c = b;
|
||||
a += ( f + k[i] + in[g] );
|
||||
a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
|
||||
b += a;
|
||||
a = temp;
|
||||
step = &md5_steps[ i / 16 ];
|
||||
f = step->f ( &u.v );
|
||||
g = ( ( ( step->coefficient * i ) + step->constant ) % 16 );
|
||||
temp = *d;
|
||||
*d = *c;
|
||||
*c = *b;
|
||||
*b = ( *b + rol32 ( ( *a + f + k[i] + w[g] ), r[i] ) );
|
||||
*a = temp;
|
||||
DBGC2 ( context, "%2d : %08x %08x %08x %08x\n",
|
||||
i, *a, *b, *c, *d );
|
||||
}
|
||||
|
||||
hash[0] += a;
|
||||
hash[1] += b;
|
||||
hash[2] += c;
|
||||
hash[3] += d;
|
||||
/* Add chunk to hash and convert back to big-endian */
|
||||
for ( i = 0 ; i < 4 ; i++ ) {
|
||||
context->ddd.dd.digest.h[i] =
|
||||
cpu_to_le32 ( context->ddd.dd.digest.h[i] +
|
||||
u.ddd.dd.digest.h[i] );
|
||||
}
|
||||
|
||||
DBGC ( context, "MD5 digested:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
}
|
||||
|
||||
/* XXX: this stuff can be optimized */
|
||||
static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
|
||||
{
|
||||
while (words--) {
|
||||
le32_to_cpus(buf);
|
||||
buf++;
|
||||
/**
|
||||
* Accumulate data with MD5 algorithm
|
||||
*
|
||||
* @v ctx MD5 context
|
||||
* @v data Data
|
||||
* @v len Length of data
|
||||
*/
|
||||
static void md5_update ( void *ctx, const void *data, size_t len ) {
|
||||
struct md5_context *context = ctx;
|
||||
const uint8_t *byte = data;
|
||||
size_t offset;
|
||||
|
||||
/* Accumulate data a byte at a time, performing the digest
|
||||
* whenever we fill the data buffer
|
||||
*/
|
||||
while ( len-- ) {
|
||||
offset = ( context->len % sizeof ( context->ddd.dd.data ) );
|
||||
context->ddd.dd.data.byte[offset] = *(byte++);
|
||||
context->len++;
|
||||
if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
|
||||
md5_digest ( context );
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
|
||||
{
|
||||
while (words--) {
|
||||
cpu_to_le32s(buf);
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void md5_transform_helper(struct md5_ctx *ctx)
|
||||
{
|
||||
le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
|
||||
md5_transform(ctx->hash, ctx->block);
|
||||
}
|
||||
|
||||
static void md5_init(void *context)
|
||||
{
|
||||
struct md5_ctx *mctx = context;
|
||||
|
||||
mctx->hash[0] = 0x67452301;
|
||||
mctx->hash[1] = 0xefcdab89;
|
||||
mctx->hash[2] = 0x98badcfe;
|
||||
mctx->hash[3] = 0x10325476;
|
||||
mctx->byte_count = 0;
|
||||
}
|
||||
|
||||
static void md5_update(void *context, const void *data, size_t len)
|
||||
{
|
||||
struct md5_ctx *mctx = context;
|
||||
const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
|
||||
|
||||
mctx->byte_count += len;
|
||||
|
||||
if (avail > len) {
|
||||
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
|
||||
data, len);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
|
||||
data, avail);
|
||||
|
||||
md5_transform_helper(mctx);
|
||||
data += avail;
|
||||
len -= avail;
|
||||
|
||||
while (len >= sizeof(mctx->block)) {
|
||||
memcpy(mctx->block, data, sizeof(mctx->block));
|
||||
md5_transform_helper(mctx);
|
||||
data += sizeof(mctx->block);
|
||||
len -= sizeof(mctx->block);
|
||||
}
|
||||
|
||||
memcpy(mctx->block, data, len);
|
||||
}
|
||||
|
||||
static void md5_final(void *context, void *out)
|
||||
{
|
||||
struct md5_ctx *mctx = context;
|
||||
const unsigned int offset = mctx->byte_count & 0x3f;
|
||||
char *p = (char *)mctx->block + offset;
|
||||
int padding = 56 - (offset + 1);
|
||||
|
||||
*p++ = 0x80;
|
||||
if (padding < 0) {
|
||||
memset(p, 0x00, padding + sizeof (u64));
|
||||
md5_transform_helper(mctx);
|
||||
p = (char *)mctx->block;
|
||||
padding = 56;
|
||||
}
|
||||
|
||||
memset(p, 0, padding);
|
||||
mctx->block[14] = mctx->byte_count << 3;
|
||||
mctx->block[15] = mctx->byte_count >> 29;
|
||||
le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
|
||||
sizeof(u64)) / sizeof(u32));
|
||||
md5_transform(mctx->hash, mctx->block);
|
||||
cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
|
||||
memcpy(out, mctx->hash, sizeof(mctx->hash));
|
||||
memset(mctx, 0, sizeof(*mctx));
|
||||
/**
|
||||
* Generate MD5 digest
|
||||
*
|
||||
* @v ctx MD5 context
|
||||
* @v out Output buffer
|
||||
*/
|
||||
static void md5_final ( void *ctx, void *out ) {
|
||||
struct md5_context *context = ctx;
|
||||
uint64_t len_bits;
|
||||
uint8_t pad;
|
||||
|
||||
/* Record length before pre-processing */
|
||||
len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 );
|
||||
|
||||
/* Pad with a single "1" bit followed by as many "0" bits as required */
|
||||
pad = 0x80;
|
||||
do {
|
||||
md5_update ( ctx, &pad, sizeof ( pad ) );
|
||||
pad = 0x00;
|
||||
} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
|
||||
offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
|
||||
|
||||
/* Append length (in bits) */
|
||||
md5_update ( ctx, &len_bits, sizeof ( len_bits ) );
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
|
||||
/* Copy out final digest */
|
||||
memcpy ( out, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
}
|
||||
|
||||
/** MD5 algorithm */
|
||||
struct digest_algorithm md5_algorithm = {
|
||||
.name = "md5",
|
||||
.ctxsize = MD5_CTX_SIZE,
|
||||
.blocksize = ( MD5_BLOCK_WORDS * 4 ),
|
||||
.digestsize = MD5_DIGEST_SIZE,
|
||||
.ctxsize = sizeof ( struct md5_context ),
|
||||
.blocksize = sizeof ( union md5_block ),
|
||||
.digestsize = sizeof ( struct md5_digest ),
|
||||
.init = md5_init,
|
||||
.update = md5_update,
|
||||
.final = md5_final,
|
||||
};
|
||||
|
||||
/** "md5" object identifier */
|
||||
static uint8_t oid_md5[] = { ASN1_OID_MD5 };
|
||||
|
||||
/** "md5" OID-identified algorithm */
|
||||
struct asn1_algorithm oid_md5_algorithm __asn1_algorithm = {
|
||||
.name = "md5",
|
||||
.digest = &md5_algorithm,
|
||||
.oid = ASN1_OID_CURSOR ( oid_md5 ),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Nonexistent entropy source
|
||||
*
|
||||
*
|
||||
* This source provides no entropy and must NOT be used in a
|
||||
* security-sensitive environment.
|
||||
*/
|
||||
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample );
|
||||
PROVIDE_ENTROPY_INLINE ( null, entropy_enable );
|
||||
PROVIDE_ENTROPY_INLINE ( null, entropy_disable );
|
||||
PROVIDE_ENTROPY_INLINE ( null, get_noise );
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Random non-zero bytes
|
||||
*
|
||||
* The RSA algorithm requires the generation of random non-zero bytes,
|
||||
* i.e. bytes in the range [0x01,0xff].
|
||||
*
|
||||
* This algorithm is designed to comply with ANS X9.82 Part 1-2006
|
||||
* Section 9.2.1. This standard is not freely available, but most of
|
||||
* the text appears to be shared with NIST SP 800-90, which can be
|
||||
* downloaded from
|
||||
*
|
||||
* http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
|
||||
*
|
||||
* Where possible, references are given to both documents. In the
|
||||
* case of any disagreement, ANS X9.82 takes priority over NIST SP
|
||||
* 800-90. (In particular, note that some algorithms that are
|
||||
* Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <ipxe/rbg.h>
|
||||
#include <ipxe/random_nz.h>
|
||||
|
||||
/**
|
||||
* Get random non-zero bytes
|
||||
*
|
||||
* @v data Output buffer
|
||||
* @v len Length of output buffer
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This algorithm is designed to be isomorphic to the Simple Discard
|
||||
* Method described in ANS X9.82 Part 1-2006 Section 9.2.1 (NIST SP
|
||||
* 800-90 Section B.5.1.1).
|
||||
*/
|
||||
int get_random_nz ( void *data, size_t len ) {
|
||||
uint8_t *bytes = data;
|
||||
int rc;
|
||||
|
||||
while ( len ) {
|
||||
|
||||
/* Generate random byte */
|
||||
if ( ( rc = rbg_generate ( NULL, 0, 0, bytes, 1 ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Move to next byte if this byte is acceptable */
|
||||
if ( *bytes != 0 ) {
|
||||
bytes++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RBG mechanism
|
||||
*
|
||||
* This mechanism is designed to comply with ANS X9.82 Part 4 (April
|
||||
* 2011 Draft) Section 10. This standard is unfortunately not freely
|
||||
* available.
|
||||
*
|
||||
* The chosen RBG design is that of a DRBG with a live entropy source
|
||||
* with no conditioning function. Only a single security strength is
|
||||
* supported. No seedfile is used since there may be no non-volatile
|
||||
* storage available. The system UUID is used as the personalisation
|
||||
* string.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/uuid.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/drbg.h>
|
||||
#include <ipxe/rbg.h>
|
||||
|
||||
/** The RBG */
|
||||
struct random_bit_generator rbg;
|
||||
|
||||
/**
|
||||
* Start up RBG
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This is the RBG_Startup function defined in ANS X9.82 Part 4 (April
|
||||
* 2011 Draft) Section 9.1.2.2.
|
||||
*/
|
||||
static int rbg_startup ( void ) {
|
||||
union uuid uuid;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Try to obtain system UUID for use as personalisation
|
||||
* string, in accordance with ANS X9.82 Part 3-2007 Section
|
||||
* 8.5.2. If no UUID is available, proceed without a
|
||||
* personalisation string.
|
||||
*/
|
||||
if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( &rbg, "RBG could not fetch personalisation string: "
|
||||
"%s\n", strerror ( rc ) );
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Instantiate DRBG */
|
||||
if ( ( rc = drbg_instantiate ( &rbg.state, &uuid, len ) ) != 0 ) {
|
||||
DBGC ( &rbg, "RBG could not instantiate DRBG: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down RBG
|
||||
*
|
||||
*/
|
||||
static void rbg_shutdown ( void ) {
|
||||
|
||||
/* Uninstantiate DRBG */
|
||||
drbg_uninstantiate ( &rbg.state );
|
||||
}
|
||||
|
||||
/** RBG startup function */
|
||||
static void rbg_startup_fn ( void ) {
|
||||
|
||||
/* Start up RBG. There is no way to report an error at this
|
||||
* stage, but a failed startup will result in an invalid DRBG
|
||||
* that refuses to generate bits.
|
||||
*/
|
||||
rbg_startup();
|
||||
}
|
||||
|
||||
/** RBG shutdown function */
|
||||
static void rbg_shutdown_fn ( int booting __unused ) {
|
||||
|
||||
/* Shut down RBG */
|
||||
rbg_shutdown();
|
||||
}
|
||||
|
||||
/** RBG startup table entry */
|
||||
struct startup_fn startup_rbg __startup_fn ( STARTUP_NORMAL ) = {
|
||||
.startup = rbg_startup_fn,
|
||||
.shutdown = rbg_shutdown_fn,
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/dhcp.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/rootcert.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Root certificate store
|
||||
*
|
||||
*/
|
||||
|
||||
/** Length of a root certificate fingerprint */
|
||||
#define FINGERPRINT_LEN SHA256_DIGEST_SIZE
|
||||
|
||||
/* Allow trusted certificates to be overridden if not explicitly specified */
|
||||
#ifdef TRUSTED
|
||||
#define ALLOW_TRUST_OVERRIDE 0
|
||||
#else
|
||||
#define ALLOW_TRUST_OVERRIDE 1
|
||||
#endif
|
||||
|
||||
/* Use iPXE root CA if no trusted certificates are explicitly specified */
|
||||
#ifndef TRUSTED
|
||||
#define TRUSTED \
|
||||
/* iPXE root CA */ \
|
||||
0x9f, 0xaf, 0x71, 0x7b, 0x7f, 0x8c, 0xa2, 0xf9, 0x3c, 0x25, \
|
||||
0x6c, 0x79, 0xf8, 0xac, 0x55, 0x91, 0x89, 0x5d, 0x66, 0xd1, \
|
||||
0xff, 0x3b, 0xee, 0x63, 0x97, 0xa7, 0x0d, 0x29, 0xc6, 0x5e, \
|
||||
0xed, 0x1a,
|
||||
#endif
|
||||
|
||||
/** Root certificate fingerprints */
|
||||
static const uint8_t fingerprints[] = { TRUSTED };
|
||||
|
||||
/** Root certificate fingerprint setting */
|
||||
static struct setting trust_setting __setting ( SETTING_CRYPTO ) = {
|
||||
.name = "trust",
|
||||
.description = "Trusted root certificate fingerprints",
|
||||
.tag = DHCP_EB_TRUST,
|
||||
.type = &setting_type_hex,
|
||||
};
|
||||
|
||||
/** Root certificates */
|
||||
struct x509_root root_certificates = {
|
||||
.digest = &sha256_algorithm,
|
||||
.count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ),
|
||||
.fingerprints = fingerprints,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise root certificate
|
||||
*
|
||||
* The list of trusted root certificates can be specified at build
|
||||
* time using the TRUST= build parameter. If no certificates are
|
||||
* specified, then the default iPXE root CA certificate is trusted.
|
||||
*
|
||||
* If no certificates were explicitly specified, then we allow the
|
||||
* list of trusted root certificate fingerprints to be overridden
|
||||
* using the "trust" setting, but only at the point of iPXE
|
||||
* initialisation. This prevents untrusted sources of settings
|
||||
* (e.g. DHCP) from subverting the chain of trust, while allowing
|
||||
* trustworthy sources (e.g. VMware GuestInfo or non-volatile stored
|
||||
* options) to specify the trusted root certificate without requiring
|
||||
* a rebuild.
|
||||
*/
|
||||
static void rootcert_init ( void ) {
|
||||
void *external = NULL;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Allow trusted root certificates to be overridden only if
|
||||
* not explicitly specified at build time.
|
||||
*/
|
||||
if ( ALLOW_TRUST_OVERRIDE ) {
|
||||
|
||||
/* Fetch copy of "trust" setting, if it exists. This
|
||||
* memory will never be freed.
|
||||
*/
|
||||
len = fetch_setting_copy ( NULL, &trust_setting, &external );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( &root_certificates, "ROOTCERT cannot fetch "
|
||||
"trusted root certificate fingerprints: %s\n",
|
||||
strerror ( rc ) );
|
||||
/* No way to prevent startup; fail safe by
|
||||
* trusting no certificates.
|
||||
*/
|
||||
root_certificates.count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use certificates from "trust" setting, if present */
|
||||
if ( external ) {
|
||||
root_certificates.fingerprints = external;
|
||||
root_certificates.count = ( len / FINGERPRINT_LEN );
|
||||
}
|
||||
}
|
||||
|
||||
DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n",
|
||||
root_certificates.count, ( external ? "external" : "built-in" ));
|
||||
DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints,
|
||||
( root_certificates.count * FINGERPRINT_LEN ) );
|
||||
}
|
||||
|
||||
/** Root certificate initialiser */
|
||||
struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = {
|
||||
.initialise = rootcert_init,
|
||||
};
|
||||
@@ -0,0 +1,648 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/bigint.h>
|
||||
#include <ipxe/random_nz.h>
|
||||
#include <ipxe/md5.h>
|
||||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/rsa.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RSA public-key cryptography
|
||||
*
|
||||
* RSA is documented in RFC 3447.
|
||||
*/
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EACCES_VERIFY \
|
||||
__einfo_error ( EINFO_EACCES_VERIFY )
|
||||
#define EINFO_EACCES_VERIFY \
|
||||
__einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" )
|
||||
|
||||
/** "rsaEncryption" object identifier */
|
||||
static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION };
|
||||
|
||||
/** "md5WithRSAEncryption" object identifier */
|
||||
static uint8_t oid_md5_with_rsa_encryption[] =
|
||||
{ ASN1_OID_MD5WITHRSAENCRYPTION };
|
||||
|
||||
/** "sha1WithRSAEncryption" object identifier */
|
||||
static uint8_t oid_sha1_with_rsa_encryption[] =
|
||||
{ ASN1_OID_SHA1WITHRSAENCRYPTION };
|
||||
|
||||
/** "sha256WithRSAEncryption" object identifier */
|
||||
static uint8_t oid_sha256_with_rsa_encryption[] =
|
||||
{ ASN1_OID_SHA256WITHRSAENCRYPTION };
|
||||
|
||||
/** "rsaEncryption" OID-identified algorithm */
|
||||
struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
|
||||
.name = "rsaEncryption",
|
||||
.pubkey = &rsa_algorithm,
|
||||
.digest = NULL,
|
||||
.oid = ASN1_OID_CURSOR ( oid_rsa_encryption ),
|
||||
};
|
||||
|
||||
/** "md5WithRSAEncryption" OID-identified algorithm */
|
||||
struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = {
|
||||
.name = "md5WithRSAEncryption",
|
||||
.pubkey = &rsa_algorithm,
|
||||
.digest = &md5_algorithm,
|
||||
.oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ),
|
||||
};
|
||||
|
||||
/** "sha1WithRSAEncryption" OID-identified algorithm */
|
||||
struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = {
|
||||
.name = "sha1WithRSAEncryption",
|
||||
.pubkey = &rsa_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
.oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ),
|
||||
};
|
||||
|
||||
/** "sha256WithRSAEncryption" OID-identified algorithm */
|
||||
struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = {
|
||||
.name = "sha256WithRSAEncryption",
|
||||
.pubkey = &rsa_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
.oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ),
|
||||
};
|
||||
|
||||
/** MD5 digestInfo prefix */
|
||||
static const uint8_t rsa_md5_prefix_data[] =
|
||||
{ RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) };
|
||||
|
||||
/** SHA-1 digestInfo prefix */
|
||||
static const uint8_t rsa_sha1_prefix_data[] =
|
||||
{ RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) };
|
||||
|
||||
/** SHA-256 digestInfo prefix */
|
||||
static const uint8_t rsa_sha256_prefix_data[] =
|
||||
{ RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) };
|
||||
|
||||
/** MD5 digestInfo prefix */
|
||||
struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = {
|
||||
.digest = &md5_algorithm,
|
||||
.data = rsa_md5_prefix_data,
|
||||
.len = sizeof ( rsa_md5_prefix_data ),
|
||||
};
|
||||
|
||||
/** SHA-1 digestInfo prefix */
|
||||
struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = {
|
||||
.digest = &sha1_algorithm,
|
||||
.data = rsa_sha1_prefix_data,
|
||||
.len = sizeof ( rsa_sha1_prefix_data ),
|
||||
};
|
||||
|
||||
/** SHA-256 digestInfo prefix */
|
||||
struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = {
|
||||
.digest = &sha256_algorithm,
|
||||
.data = rsa_sha256_prefix_data,
|
||||
.len = sizeof ( rsa_sha256_prefix_data ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Identify RSA prefix
|
||||
*
|
||||
* @v digest Digest algorithm
|
||||
* @ret prefix RSA prefix, or NULL
|
||||
*/
|
||||
static struct rsa_digestinfo_prefix *
|
||||
rsa_find_prefix ( struct digest_algorithm *digest ) {
|
||||
struct rsa_digestinfo_prefix *prefix;
|
||||
|
||||
for_each_table_entry ( prefix, RSA_DIGESTINFO_PREFIXES ) {
|
||||
if ( prefix->digest == digest )
|
||||
return prefix;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free RSA dynamic storage
|
||||
*
|
||||
* @v context RSA context
|
||||
*/
|
||||
static void rsa_free ( struct rsa_context *context ) {
|
||||
|
||||
free ( context->dynamic );
|
||||
context->dynamic = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate RSA dynamic storage
|
||||
*
|
||||
* @v context RSA context
|
||||
* @v modulus_len Modulus length
|
||||
* @v exponent_len Exponent length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rsa_alloc ( struct rsa_context *context, size_t modulus_len,
|
||||
size_t exponent_len ) {
|
||||
unsigned int size = bigint_required_size ( modulus_len );
|
||||
unsigned int exponent_size = bigint_required_size ( exponent_len );
|
||||
bigint_t ( size ) *modulus;
|
||||
bigint_t ( exponent_size ) *exponent;
|
||||
size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent );
|
||||
struct {
|
||||
bigint_t ( size ) modulus;
|
||||
bigint_t ( exponent_size ) exponent;
|
||||
bigint_t ( size ) input;
|
||||
bigint_t ( size ) output;
|
||||
uint8_t tmp[tmp_len];
|
||||
} __attribute__ (( packed )) *dynamic;
|
||||
|
||||
/* Free any existing dynamic storage */
|
||||
rsa_free ( context );
|
||||
|
||||
/* Allocate dynamic storage */
|
||||
dynamic = malloc ( sizeof ( *dynamic ) );
|
||||
if ( ! dynamic )
|
||||
return -ENOMEM;
|
||||
|
||||
/* Assign dynamic storage */
|
||||
context->dynamic = dynamic;
|
||||
context->modulus0 = &dynamic->modulus.element[0];
|
||||
context->size = size;
|
||||
context->max_len = modulus_len;
|
||||
context->exponent0 = &dynamic->exponent.element[0];
|
||||
context->exponent_size = exponent_size;
|
||||
context->input0 = &dynamic->input.element[0];
|
||||
context->output0 = &dynamic->output.element[0];
|
||||
context->tmp = &dynamic->tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse RSA integer
|
||||
*
|
||||
* @v context RSA context
|
||||
* @v integer Integer to fill in
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rsa_parse_integer ( struct rsa_context *context,
|
||||
struct asn1_cursor *integer,
|
||||
const struct asn1_cursor *raw ) {
|
||||
|
||||
/* Enter integer */
|
||||
memcpy ( integer, raw, sizeof ( *integer ) );
|
||||
asn1_enter ( integer, ASN1_INTEGER );
|
||||
|
||||
/* Skip initial sign byte if applicable */
|
||||
if ( ( integer->len > 1 ) &&
|
||||
( *( ( uint8_t * ) integer->data ) == 0x00 ) ) {
|
||||
integer->data++;
|
||||
integer->len--;
|
||||
}
|
||||
|
||||
/* Fail if cursor or integer are invalid */
|
||||
if ( ! integer->len ) {
|
||||
DBGC ( context, "RSA %p invalid integer:\n", context );
|
||||
DBGC_HDA ( context, 0, raw->data, raw->len );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise RSA cipher
|
||||
*
|
||||
* @v ctx RSA context
|
||||
* @v key Key
|
||||
* @v key_len Length of key
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rsa_init ( void *ctx, const void *key, size_t key_len ) {
|
||||
struct rsa_context *context = ctx;
|
||||
const struct asn1_bit_string *bit_string;
|
||||
struct asn1_cursor modulus;
|
||||
struct asn1_cursor exponent;
|
||||
struct asn1_cursor cursor;
|
||||
int is_private;
|
||||
int rc;
|
||||
|
||||
/* Initialise context */
|
||||
memset ( context, 0, sizeof ( *context ) );
|
||||
|
||||
/* Initialise cursor */
|
||||
cursor.data = key;
|
||||
cursor.len = key_len;
|
||||
|
||||
/* Enter subjectPublicKeyInfo/RSAPrivateKey */
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Determine key format */
|
||||
if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
|
||||
/* Private key */
|
||||
is_private = 1;
|
||||
|
||||
/* Skip version */
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
} else {
|
||||
/* Public key */
|
||||
is_private = 0;
|
||||
|
||||
/* Skip algorithm */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE );
|
||||
|
||||
/* Enter subjectPublicKey */
|
||||
asn1_enter ( &cursor, ASN1_BIT_STRING );
|
||||
|
||||
/* Check and skip unused-bits byte of bit string */
|
||||
bit_string = cursor.data;
|
||||
if ( ( cursor.len < sizeof ( *bit_string ) ) ||
|
||||
( bit_string->unused != 0 ) ) {
|
||||
rc = -EINVAL;
|
||||
goto err_parse;
|
||||
}
|
||||
cursor.data = &bit_string->data;
|
||||
cursor.len -= offsetof ( typeof ( *bit_string ), data );
|
||||
|
||||
/* Enter RSAPublicKey */
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
}
|
||||
|
||||
/* Extract modulus */
|
||||
if ( ( rc = rsa_parse_integer ( context, &modulus, &cursor ) ) != 0 )
|
||||
goto err_parse;
|
||||
asn1_skip_any ( &cursor );
|
||||
|
||||
/* Skip public exponent, if applicable */
|
||||
if ( is_private )
|
||||
asn1_skip ( &cursor, ASN1_INTEGER );
|
||||
|
||||
/* Extract publicExponent/privateExponent */
|
||||
if ( ( rc = rsa_parse_integer ( context, &exponent, &cursor ) ) != 0 )
|
||||
goto err_parse;
|
||||
|
||||
DBGC ( context, "RSA %p modulus:\n", context );
|
||||
DBGC_HDA ( context, 0, modulus.data, modulus.len );
|
||||
DBGC ( context, "RSA %p exponent:\n", context );
|
||||
DBGC_HDA ( context, 0, exponent.data, exponent.len );
|
||||
|
||||
/* Allocate dynamic storage */
|
||||
if ( ( rc = rsa_alloc ( context, modulus.len, exponent.len ) ) != 0 )
|
||||
goto err_alloc;
|
||||
|
||||
/* Construct big integers */
|
||||
bigint_init ( ( ( bigint_t ( context->size ) * ) context->modulus0 ),
|
||||
modulus.data, modulus.len );
|
||||
bigint_init ( ( ( bigint_t ( context->exponent_size ) * )
|
||||
context->exponent0 ), exponent.data, exponent.len );
|
||||
|
||||
return 0;
|
||||
|
||||
rsa_free ( context );
|
||||
err_alloc:
|
||||
err_parse:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate RSA maximum output length
|
||||
*
|
||||
* @v ctx RSA context
|
||||
* @ret max_len Maximum output length
|
||||
*/
|
||||
static size_t rsa_max_len ( void *ctx ) {
|
||||
struct rsa_context *context = ctx;
|
||||
|
||||
return context->max_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform RSA cipher operation
|
||||
*
|
||||
* @v context RSA context
|
||||
* @v in Input buffer
|
||||
* @v out Output buffer
|
||||
*/
|
||||
static void rsa_cipher ( struct rsa_context *context,
|
||||
const void *in, void *out ) {
|
||||
bigint_t ( context->size ) *input = ( ( void * ) context->input0 );
|
||||
bigint_t ( context->size ) *output = ( ( void * ) context->output0 );
|
||||
bigint_t ( context->size ) *modulus = ( ( void * ) context->modulus0 );
|
||||
bigint_t ( context->exponent_size ) *exponent =
|
||||
( ( void * ) context->exponent0 );
|
||||
|
||||
/* Initialise big integer */
|
||||
bigint_init ( input, in, context->max_len );
|
||||
|
||||
/* Perform modular exponentiation */
|
||||
bigint_mod_exp ( input, modulus, exponent, output, context->tmp );
|
||||
|
||||
/* Copy out result */
|
||||
bigint_done ( output, out, context->max_len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt using RSA
|
||||
*
|
||||
* @v ctx RSA context
|
||||
* @v plaintext Plaintext
|
||||
* @v plaintext_len Length of plaintext
|
||||
* @v ciphertext Ciphertext
|
||||
* @ret ciphertext_len Length of ciphertext, or negative error
|
||||
*/
|
||||
static int rsa_encrypt ( void *ctx, const void *plaintext,
|
||||
size_t plaintext_len, void *ciphertext ) {
|
||||
struct rsa_context *context = ctx;
|
||||
void *temp;
|
||||
uint8_t *encoded;
|
||||
size_t max_len = ( context->max_len - 11 );
|
||||
size_t random_nz_len = ( max_len - plaintext_len + 8 );
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( plaintext_len > max_len ) {
|
||||
DBGC ( context, "RSA %p plaintext too long (%zd bytes, max "
|
||||
"%zd)\n", context, plaintext_len, max_len );
|
||||
return -ERANGE;
|
||||
}
|
||||
DBGC ( context, "RSA %p encrypting:\n", context );
|
||||
DBGC_HDA ( context, 0, plaintext, plaintext_len );
|
||||
|
||||
/* Construct encoded message (using the big integer output
|
||||
* buffer as temporary storage)
|
||||
*/
|
||||
temp = context->output0;
|
||||
encoded = temp;
|
||||
encoded[0] = 0x00;
|
||||
encoded[1] = 0x02;
|
||||
if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) {
|
||||
DBGC ( context, "RSA %p could not generate random data: %s\n",
|
||||
context, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
encoded[ 2 + random_nz_len ] = 0x00;
|
||||
memcpy ( &encoded[ context->max_len - plaintext_len ],
|
||||
plaintext, plaintext_len );
|
||||
|
||||
/* Encipher the encoded message */
|
||||
rsa_cipher ( context, encoded, ciphertext );
|
||||
DBGC ( context, "RSA %p encrypted:\n", context );
|
||||
DBGC_HDA ( context, 0, ciphertext, context->max_len );
|
||||
|
||||
return context->max_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt using RSA
|
||||
*
|
||||
* @v ctx RSA context
|
||||
* @v ciphertext Ciphertext
|
||||
* @v ciphertext_len Ciphertext length
|
||||
* @v plaintext Plaintext
|
||||
* @ret plaintext_len Plaintext length, or negative error
|
||||
*/
|
||||
static int rsa_decrypt ( void *ctx, const void *ciphertext,
|
||||
size_t ciphertext_len, void *plaintext ) {
|
||||
struct rsa_context *context = ctx;
|
||||
void *temp;
|
||||
uint8_t *encoded;
|
||||
uint8_t *end;
|
||||
uint8_t *zero;
|
||||
uint8_t *start;
|
||||
size_t plaintext_len;
|
||||
|
||||
/* Sanity check */
|
||||
if ( ciphertext_len != context->max_len ) {
|
||||
DBGC ( context, "RSA %p ciphertext incorrect length (%zd "
|
||||
"bytes, should be %zd)\n",
|
||||
context, ciphertext_len, context->max_len );
|
||||
return -ERANGE;
|
||||
}
|
||||
DBGC ( context, "RSA %p decrypting:\n", context );
|
||||
DBGC_HDA ( context, 0, ciphertext, ciphertext_len );
|
||||
|
||||
/* Decipher the message (using the big integer input buffer as
|
||||
* temporary storage)
|
||||
*/
|
||||
temp = context->input0;
|
||||
encoded = temp;
|
||||
rsa_cipher ( context, ciphertext, encoded );
|
||||
|
||||
/* Parse the message */
|
||||
end = ( encoded + context->max_len );
|
||||
if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) )
|
||||
goto invalid;
|
||||
zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) );
|
||||
if ( ! zero )
|
||||
goto invalid;
|
||||
start = ( zero + 1 );
|
||||
plaintext_len = ( end - start );
|
||||
|
||||
/* Copy out message */
|
||||
memcpy ( plaintext, start, plaintext_len );
|
||||
DBGC ( context, "RSA %p decrypted:\n", context );
|
||||
DBGC_HDA ( context, 0, plaintext, plaintext_len );
|
||||
|
||||
return plaintext_len;
|
||||
|
||||
invalid:
|
||||
DBGC ( context, "RSA %p invalid decrypted message:\n", context );
|
||||
DBGC_HDA ( context, 0, encoded, context->max_len );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode RSA digest
|
||||
*
|
||||
* @v context RSA context
|
||||
* @v digest Digest algorithm
|
||||
* @v value Digest value
|
||||
* @v encoded Encoded digest
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rsa_encode_digest ( struct rsa_context *context,
|
||||
struct digest_algorithm *digest,
|
||||
const void *value, void *encoded ) {
|
||||
struct rsa_digestinfo_prefix *prefix;
|
||||
size_t digest_len = digest->digestsize;
|
||||
uint8_t *temp = encoded;
|
||||
size_t digestinfo_len;
|
||||
size_t max_len;
|
||||
size_t pad_len;
|
||||
|
||||
/* Identify prefix */
|
||||
prefix = rsa_find_prefix ( digest );
|
||||
if ( ! prefix ) {
|
||||
DBGC ( context, "RSA %p has no prefix for %s\n",
|
||||
context, digest->name );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
digestinfo_len = ( prefix->len + digest_len );
|
||||
|
||||
/* Sanity check */
|
||||
max_len = ( context->max_len - 11 );
|
||||
if ( digestinfo_len > max_len ) {
|
||||
DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max"
|
||||
"%zd)\n",
|
||||
context, digest->name, digestinfo_len, max_len );
|
||||
return -ERANGE;
|
||||
}
|
||||
DBGC ( context, "RSA %p encoding %s digest:\n",
|
||||
context, digest->name );
|
||||
DBGC_HDA ( context, 0, value, digest_len );
|
||||
|
||||
/* Construct encoded message */
|
||||
*(temp++) = 0x00;
|
||||
*(temp++) = 0x01;
|
||||
pad_len = ( max_len - digestinfo_len + 8 );
|
||||
memset ( temp, 0xff, pad_len );
|
||||
temp += pad_len;
|
||||
*(temp++) = 0x00;
|
||||
memcpy ( temp, prefix->data, prefix->len );
|
||||
temp += prefix->len;
|
||||
memcpy ( temp, value, digest_len );
|
||||
temp += digest_len;
|
||||
assert ( temp == ( encoded + context->max_len ) );
|
||||
DBGC ( context, "RSA %p encoded %s digest:\n", context, digest->name );
|
||||
DBGC_HDA ( context, 0, encoded, context->max_len );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign digest value using RSA
|
||||
*
|
||||
* @v ctx RSA context
|
||||
* @v digest Digest algorithm
|
||||
* @v value Digest value
|
||||
* @v signature Signature
|
||||
* @ret signature_len Signature length, or negative error
|
||||
*/
|
||||
static int rsa_sign ( void *ctx, struct digest_algorithm *digest,
|
||||
const void *value, void *signature ) {
|
||||
struct rsa_context *context = ctx;
|
||||
void *temp;
|
||||
int rc;
|
||||
|
||||
DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name );
|
||||
DBGC_HDA ( context, 0, value, digest->digestsize );
|
||||
|
||||
/* Encode digest (using the big integer output buffer as
|
||||
* temporary storage)
|
||||
*/
|
||||
temp = context->output0;
|
||||
if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Encipher the encoded digest */
|
||||
rsa_cipher ( context, temp, signature );
|
||||
DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name );
|
||||
DBGC_HDA ( context, 0, signature, context->max_len );
|
||||
|
||||
return context->max_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify signed digest value using RSA
|
||||
*
|
||||
* @v ctx RSA context
|
||||
* @v digest Digest algorithm
|
||||
* @v value Digest value
|
||||
* @v signature Signature
|
||||
* @v signature_len Signature length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rsa_verify ( void *ctx, struct digest_algorithm *digest,
|
||||
const void *value, const void *signature,
|
||||
size_t signature_len ) {
|
||||
struct rsa_context *context = ctx;
|
||||
void *temp;
|
||||
void *expected;
|
||||
void *actual;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( signature_len != context->max_len ) {
|
||||
DBGC ( context, "RSA %p signature incorrect length (%zd "
|
||||
"bytes, should be %zd)\n",
|
||||
context, signature_len, context->max_len );
|
||||
return -ERANGE;
|
||||
}
|
||||
DBGC ( context, "RSA %p verifying %s digest:\n",
|
||||
context, digest->name );
|
||||
DBGC_HDA ( context, 0, value, digest->digestsize );
|
||||
DBGC_HDA ( context, 0, signature, signature_len );
|
||||
|
||||
/* Decipher the signature (using the big integer input buffer
|
||||
* as temporary storage)
|
||||
*/
|
||||
temp = context->input0;
|
||||
expected = temp;
|
||||
rsa_cipher ( context, signature, expected );
|
||||
DBGC ( context, "RSA %p deciphered signature:\n", context );
|
||||
DBGC_HDA ( context, 0, expected, context->max_len );
|
||||
|
||||
/* Encode digest (using the big integer output buffer as
|
||||
* temporary storage)
|
||||
*/
|
||||
temp = context->output0;
|
||||
actual = temp;
|
||||
if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 )
|
||||
return rc;
|
||||
|
||||
/* Verify the signature */
|
||||
if ( memcmp ( actual, expected, context->max_len ) != 0 ) {
|
||||
DBGC ( context, "RSA %p signature verification failed\n",
|
||||
context );
|
||||
return -EACCES_VERIFY;
|
||||
}
|
||||
|
||||
DBGC ( context, "RSA %p signature verified successfully\n", context );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise RSA cipher
|
||||
*
|
||||
* @v ctx RSA context
|
||||
*/
|
||||
static void rsa_final ( void *ctx ) {
|
||||
struct rsa_context *context = ctx;
|
||||
|
||||
rsa_free ( context );
|
||||
}
|
||||
|
||||
/** RSA public-key algorithm */
|
||||
struct pubkey_algorithm rsa_algorithm = {
|
||||
.name = "rsa",
|
||||
.ctxsize = sizeof ( struct rsa_context ),
|
||||
.init = rsa_init,
|
||||
.max_len = rsa_max_len,
|
||||
.encrypt = rsa_encrypt,
|
||||
.decrypt = rsa_decrypt,
|
||||
.sign = rsa_sign,
|
||||
.verify = rsa_verify,
|
||||
.final = rsa_final,
|
||||
};
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* SHA-1 algorithm
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <byteswap.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/rotate.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/sha1.h>
|
||||
|
||||
/** SHA-1 variables */
|
||||
struct sha1_variables {
|
||||
/* This layout matches that of struct sha1_digest_data,
|
||||
* allowing for efficient endianness-conversion,
|
||||
*/
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
uint32_t e;
|
||||
uint32_t w[80];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/**
|
||||
* f(a,b,c,d) for steps 0 to 19
|
||||
*
|
||||
* @v v SHA-1 variables
|
||||
* @ret f f(a,b,c,d)
|
||||
*/
|
||||
static uint32_t sha1_f_0_19 ( struct sha1_variables *v ) {
|
||||
return ( ( v->b & v->c ) | ( (~v->b) & v->d ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* f(a,b,c,d) for steps 20 to 39 and 60 to 79
|
||||
*
|
||||
* @v v SHA-1 variables
|
||||
* @ret f f(a,b,c,d)
|
||||
*/
|
||||
static uint32_t sha1_f_20_39_60_79 ( struct sha1_variables *v ) {
|
||||
return ( v->b ^ v->c ^ v->d );
|
||||
}
|
||||
|
||||
/**
|
||||
* f(a,b,c,d) for steps 40 to 59
|
||||
*
|
||||
* @v v SHA-1 variables
|
||||
* @ret f f(a,b,c,d)
|
||||
*/
|
||||
static uint32_t sha1_f_40_59 ( struct sha1_variables *v ) {
|
||||
return ( ( v->b & v->c ) | ( v->b & v->d ) | ( v->c & v->d ) );
|
||||
}
|
||||
|
||||
/** An SHA-1 step function */
|
||||
struct sha1_step {
|
||||
/**
|
||||
* Calculate f(a,b,c,d)
|
||||
*
|
||||
* @v v SHA-1 variables
|
||||
* @ret f f(a,b,c,d)
|
||||
*/
|
||||
uint32_t ( * f ) ( struct sha1_variables *v );
|
||||
/** Constant k */
|
||||
uint32_t k;
|
||||
};
|
||||
|
||||
/** SHA-1 steps */
|
||||
static struct sha1_step sha1_steps[4] = {
|
||||
/** 0 to 19 */
|
||||
{ .f = sha1_f_0_19, .k = 0x5a827999 },
|
||||
/** 20 to 39 */
|
||||
{ .f = sha1_f_20_39_60_79, .k = 0x6ed9eba1 },
|
||||
/** 40 to 59 */
|
||||
{ .f = sha1_f_40_59, .k = 0x8f1bbcdc },
|
||||
/** 60 to 79 */
|
||||
{ .f = sha1_f_20_39_60_79, .k = 0xca62c1d6 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise SHA-1 algorithm
|
||||
*
|
||||
* @v ctx SHA-1 context
|
||||
*/
|
||||
static void sha1_init ( void *ctx ) {
|
||||
struct sha1_context *context = ctx;
|
||||
|
||||
context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x67452301 );
|
||||
context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xefcdab89 );
|
||||
context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x98badcfe );
|
||||
context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0x10325476 );
|
||||
context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0xc3d2e1f0 );
|
||||
context->len = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate SHA-1 digest of accumulated data
|
||||
*
|
||||
* @v context SHA-1 context
|
||||
*/
|
||||
static void sha1_digest ( struct sha1_context *context ) {
|
||||
union {
|
||||
union sha1_digest_data_dwords ddd;
|
||||
struct sha1_variables v;
|
||||
} u;
|
||||
uint32_t *a = &u.v.a;
|
||||
uint32_t *b = &u.v.b;
|
||||
uint32_t *c = &u.v.c;
|
||||
uint32_t *d = &u.v.d;
|
||||
uint32_t *e = &u.v.e;
|
||||
uint32_t *w = u.v.w;
|
||||
uint32_t f;
|
||||
uint32_t k;
|
||||
uint32_t temp;
|
||||
struct sha1_step *step;
|
||||
unsigned int i;
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout );
|
||||
|
||||
DBGC ( context, "SHA1 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
DBGC_HDA ( context, context->len, &context->ddd.dd.data,
|
||||
sizeof ( context->ddd.dd.data ) );
|
||||
|
||||
/* Convert h[0..4] to host-endian, and initialise a, b, c, d,
|
||||
* e, and w[0..15]
|
||||
*/
|
||||
for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
|
||||
sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
|
||||
be32_to_cpus ( &context->ddd.dword[i] );
|
||||
u.ddd.dword[i] = context->ddd.dword[i];
|
||||
}
|
||||
|
||||
/* Initialise w[16..79] */
|
||||
for ( i = 16 ; i < 80 ; i++ )
|
||||
w[i] = rol32 ( ( w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ), 1 );
|
||||
|
||||
/* Main loop */
|
||||
for ( i = 0 ; i < 80 ; i++ ) {
|
||||
step = &sha1_steps[ i / 20 ];
|
||||
f = step->f ( &u.v );
|
||||
k = step->k;
|
||||
temp = ( rol32 ( *a, 5 ) + f + *e + k + w[i] );
|
||||
*e = *d;
|
||||
*d = *c;
|
||||
*c = rol32 ( *b, 30 );
|
||||
*b = *a;
|
||||
*a = temp;
|
||||
DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x\n",
|
||||
i, *a, *b, *c, *d, *e );
|
||||
}
|
||||
|
||||
/* Add chunk to hash and convert back to big-endian */
|
||||
for ( i = 0 ; i < 5 ; i++ ) {
|
||||
context->ddd.dd.digest.h[i] =
|
||||
cpu_to_be32 ( context->ddd.dd.digest.h[i] +
|
||||
u.ddd.dd.digest.h[i] );
|
||||
}
|
||||
|
||||
DBGC ( context, "SHA1 digested:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulate data with SHA-1 algorithm
|
||||
*
|
||||
* @v ctx SHA-1 context
|
||||
* @v data Data
|
||||
* @v len Length of data
|
||||
*/
|
||||
static void sha1_update ( void *ctx, const void *data, size_t len ) {
|
||||
struct sha1_context *context = ctx;
|
||||
const uint8_t *byte = data;
|
||||
size_t offset;
|
||||
|
||||
/* Accumulate data a byte at a time, performing the digest
|
||||
* whenever we fill the data buffer
|
||||
*/
|
||||
while ( len-- ) {
|
||||
offset = ( context->len % sizeof ( context->ddd.dd.data ) );
|
||||
context->ddd.dd.data.byte[offset] = *(byte++);
|
||||
context->len++;
|
||||
if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
|
||||
sha1_digest ( context );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-1 digest
|
||||
*
|
||||
* @v ctx SHA-1 context
|
||||
* @v out Output buffer
|
||||
*/
|
||||
static void sha1_final ( void *ctx, void *out ) {
|
||||
struct sha1_context *context = ctx;
|
||||
uint64_t len_bits;
|
||||
uint8_t pad;
|
||||
|
||||
/* Record length before pre-processing */
|
||||
len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
|
||||
|
||||
/* Pad with a single "1" bit followed by as many "0" bits as required */
|
||||
pad = 0x80;
|
||||
do {
|
||||
sha1_update ( ctx, &pad, sizeof ( pad ) );
|
||||
pad = 0x00;
|
||||
} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
|
||||
offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
|
||||
|
||||
/* Append length (in bits) */
|
||||
sha1_update ( ctx, &len_bits, sizeof ( len_bits ) );
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
|
||||
/* Copy out final digest */
|
||||
memcpy ( out, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
}
|
||||
|
||||
/** SHA-1 algorithm */
|
||||
struct digest_algorithm sha1_algorithm = {
|
||||
.name = "sha1",
|
||||
.ctxsize = sizeof ( struct sha1_context ),
|
||||
.blocksize = sizeof ( union sha1_block ),
|
||||
.digestsize = sizeof ( struct sha1_digest ),
|
||||
.init = sha1_init,
|
||||
.update = sha1_update,
|
||||
.final = sha1_final,
|
||||
};
|
||||
|
||||
/** "sha1" object identifier */
|
||||
static uint8_t oid_sha1[] = { ASN1_OID_SHA1 };
|
||||
|
||||
/** "sha1" OID-identified algorithm */
|
||||
struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm = {
|
||||
.name = "sha1",
|
||||
.digest = &sha1_algorithm,
|
||||
.oid = ASN1_OID_CURSOR ( oid_sha1 ),
|
||||
};
|
||||
+18
-16
@@ -18,6 +18,7 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <string.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/hmac.h>
|
||||
@@ -46,7 +47,7 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
|
||||
u8 keym[key_len]; /* modifiable copy of key */
|
||||
u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
|
||||
u8 *in_blknr; /* pointer to last byte of in, block number */
|
||||
u8 out[SHA1_SIZE]; /* HMAC-SHA1 result */
|
||||
u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */
|
||||
u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
|
||||
const size_t label_len = strlen ( label );
|
||||
|
||||
@@ -67,14 +68,14 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
|
||||
hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
|
||||
hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
|
||||
|
||||
if ( prf_len <= SHA1_SIZE ) {
|
||||
if ( prf_len <= sizeof ( out ) ) {
|
||||
memcpy ( prf, out, prf_len );
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy ( prf, out, SHA1_SIZE );
|
||||
prf_len -= SHA1_SIZE;
|
||||
prf += SHA1_SIZE;
|
||||
memcpy ( prf, out, sizeof ( out ) );
|
||||
prf_len -= sizeof ( out );
|
||||
prf += sizeof ( out );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,30 +98,31 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
|
||||
{
|
||||
u8 pass[pass_len]; /* modifiable passphrase */
|
||||
u8 in[salt_len + 4]; /* input buffer to first round */
|
||||
u8 last[SHA1_SIZE]; /* output of round N, input of N+1 */
|
||||
u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */
|
||||
u8 sha1_ctx[SHA1_CTX_SIZE];
|
||||
u8 *next_in = in; /* changed to `last' after first round */
|
||||
int next_size = sizeof ( in );
|
||||
int i, j;
|
||||
int i;
|
||||
unsigned int j;
|
||||
|
||||
blocknr = htonl ( blocknr );
|
||||
|
||||
memcpy ( pass, passphrase, pass_len );
|
||||
memcpy ( in, salt, salt_len );
|
||||
memcpy ( in + salt_len, &blocknr, 4 );
|
||||
memset ( block, 0, SHA1_SIZE );
|
||||
memset ( block, 0, sizeof ( last ) );
|
||||
|
||||
for ( i = 0; i < iterations; i++ ) {
|
||||
hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
|
||||
hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
|
||||
hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
|
||||
|
||||
for ( j = 0; j < SHA1_SIZE; j++ ) {
|
||||
for ( j = 0; j < sizeof ( last ); j++ ) {
|
||||
block[j] ^= last[j];
|
||||
}
|
||||
|
||||
next_in = last;
|
||||
next_size = SHA1_SIZE;
|
||||
next_size = sizeof ( last );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,20 +148,20 @@ void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
|
||||
const void *salt, size_t salt_len,
|
||||
int iterations, void *key, size_t key_len )
|
||||
{
|
||||
u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE;
|
||||
u32 blocks = ( key_len + SHA1_DIGEST_SIZE - 1 ) / SHA1_DIGEST_SIZE;
|
||||
u32 blk;
|
||||
u8 buf[SHA1_SIZE];
|
||||
u8 buf[SHA1_DIGEST_SIZE];
|
||||
|
||||
for ( blk = 1; blk <= blocks; blk++ ) {
|
||||
pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
|
||||
iterations, blk, buf );
|
||||
if ( key_len <= SHA1_SIZE ) {
|
||||
if ( key_len <= sizeof ( buf ) ) {
|
||||
memcpy ( key, buf, key_len );
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy ( key, buf, SHA1_SIZE );
|
||||
key_len -= SHA1_SIZE;
|
||||
key += SHA1_SIZE;
|
||||
memcpy ( key, buf, sizeof ( buf ) );
|
||||
key_len -= sizeof ( buf );
|
||||
key += sizeof ( buf );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* SHA-256 algorithm
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <byteswap.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/rotate.h>
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/sha256.h>
|
||||
|
||||
/** SHA-256 variables */
|
||||
struct sha256_variables {
|
||||
/* This layout matches that of struct sha256_digest_data,
|
||||
* allowing for efficient endianness-conversion,
|
||||
*/
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
uint32_t e;
|
||||
uint32_t f;
|
||||
uint32_t g;
|
||||
uint32_t h;
|
||||
uint32_t w[64];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** SHA-256 constants */
|
||||
static const uint32_t k[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise SHA-256 algorithm
|
||||
*
|
||||
* @v ctx SHA-256 context
|
||||
*/
|
||||
static void sha256_init ( void *ctx ) {
|
||||
struct sha256_context *context = ctx;
|
||||
|
||||
context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x6a09e667 );
|
||||
context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xbb67ae85 );
|
||||
context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x3c6ef372 );
|
||||
context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0xa54ff53a );
|
||||
context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0x510e527f );
|
||||
context->ddd.dd.digest.h[5] = cpu_to_be32 ( 0x9b05688c );
|
||||
context->ddd.dd.digest.h[6] = cpu_to_be32 ( 0x1f83d9ab );
|
||||
context->ddd.dd.digest.h[7] = cpu_to_be32 ( 0x5be0cd19 );
|
||||
context->len = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate SHA-256 digest of accumulated data
|
||||
*
|
||||
* @v context SHA-256 context
|
||||
*/
|
||||
static void sha256_digest ( struct sha256_context *context ) {
|
||||
union {
|
||||
union sha256_digest_data_dwords ddd;
|
||||
struct sha256_variables v;
|
||||
} u;
|
||||
uint32_t *a = &u.v.a;
|
||||
uint32_t *b = &u.v.b;
|
||||
uint32_t *c = &u.v.c;
|
||||
uint32_t *d = &u.v.d;
|
||||
uint32_t *e = &u.v.e;
|
||||
uint32_t *f = &u.v.f;
|
||||
uint32_t *g = &u.v.g;
|
||||
uint32_t *h = &u.v.h;
|
||||
uint32_t *w = u.v.w;
|
||||
uint32_t s0;
|
||||
uint32_t s1;
|
||||
uint32_t maj;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
uint32_t ch;
|
||||
unsigned int i;
|
||||
|
||||
/* Sanity checks */
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout );
|
||||
linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout );
|
||||
|
||||
DBGC ( context, "SHA256 digesting:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
DBGC_HDA ( context, context->len, &context->ddd.dd.data,
|
||||
sizeof ( context->ddd.dd.data ) );
|
||||
|
||||
/* Convert h[0..7] to host-endian, and initialise a, b, c, d,
|
||||
* e, f, g, h, and w[0..15]
|
||||
*/
|
||||
for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
|
||||
sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
|
||||
be32_to_cpus ( &context->ddd.dword[i] );
|
||||
u.ddd.dword[i] = context->ddd.dword[i];
|
||||
}
|
||||
|
||||
/* Initialise w[16..63] */
|
||||
for ( i = 16 ; i < 64 ; i++ ) {
|
||||
s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^
|
||||
( w[i-15] >> 3 ) );
|
||||
s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^
|
||||
( w[i-2] >> 10 ) );
|
||||
w[i] = ( w[i-16] + s0 + w[i-7] + s1 );
|
||||
}
|
||||
|
||||
/* Main loop */
|
||||
for ( i = 0 ; i < 64 ; i++ ) {
|
||||
s0 = ( ror32 ( *a, 2 ) ^ ror32 ( *a, 13 ) ^ ror32 ( *a, 22 ) );
|
||||
maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
|
||||
t2 = ( s0 + maj );
|
||||
s1 = ( ror32 ( *e, 6 ) ^ ror32 ( *e, 11 ) ^ ror32 ( *e, 25 ) );
|
||||
ch = ( ( *e & *f ) ^ ( (~*e) & *g ) );
|
||||
t1 = ( *h + s1 + ch + k[i] + w[i] );
|
||||
*h = *g;
|
||||
*g = *f;
|
||||
*f = *e;
|
||||
*e = ( *d + t1 );
|
||||
*d = *c;
|
||||
*c = *b;
|
||||
*b = *a;
|
||||
*a = ( t1 + t2 );
|
||||
DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x %08x %08x "
|
||||
"%08x\n", i, *a, *b, *c, *d, *e, *f, *g, *h );
|
||||
}
|
||||
|
||||
/* Add chunk to hash and convert back to big-endian */
|
||||
for ( i = 0 ; i < 8 ; i++ ) {
|
||||
context->ddd.dd.digest.h[i] =
|
||||
cpu_to_be32 ( context->ddd.dd.digest.h[i] +
|
||||
u.ddd.dd.digest.h[i] );
|
||||
}
|
||||
|
||||
DBGC ( context, "SHA256 digested:\n" );
|
||||
DBGC_HDA ( context, 0, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulate data with SHA-256 algorithm
|
||||
*
|
||||
* @v ctx SHA-256 context
|
||||
* @v data Data
|
||||
* @v len Length of data
|
||||
*/
|
||||
static void sha256_update ( void *ctx, const void *data, size_t len ) {
|
||||
struct sha256_context *context = ctx;
|
||||
const uint8_t *byte = data;
|
||||
size_t offset;
|
||||
|
||||
/* Accumulate data a byte at a time, performing the digest
|
||||
* whenever we fill the data buffer
|
||||
*/
|
||||
while ( len-- ) {
|
||||
offset = ( context->len % sizeof ( context->ddd.dd.data ) );
|
||||
context->ddd.dd.data.byte[offset] = *(byte++);
|
||||
context->len++;
|
||||
if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
|
||||
sha256_digest ( context );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-256 digest
|
||||
*
|
||||
* @v ctx SHA-256 context
|
||||
* @v out Output buffer
|
||||
*/
|
||||
static void sha256_final ( void *ctx, void *out ) {
|
||||
struct sha256_context *context = ctx;
|
||||
uint64_t len_bits;
|
||||
uint8_t pad;
|
||||
|
||||
/* Record length before pre-processing */
|
||||
len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
|
||||
|
||||
/* Pad with a single "1" bit followed by as many "0" bits as required */
|
||||
pad = 0x80;
|
||||
do {
|
||||
sha256_update ( ctx, &pad, sizeof ( pad ) );
|
||||
pad = 0x00;
|
||||
} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
|
||||
offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
|
||||
|
||||
/* Append length (in bits) */
|
||||
sha256_update ( ctx, &len_bits, sizeof ( len_bits ) );
|
||||
assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
|
||||
|
||||
/* Copy out final digest */
|
||||
memcpy ( out, &context->ddd.dd.digest,
|
||||
sizeof ( context->ddd.dd.digest ) );
|
||||
}
|
||||
|
||||
/** SHA-256 algorithm */
|
||||
struct digest_algorithm sha256_algorithm = {
|
||||
.name = "sha256",
|
||||
.ctxsize = sizeof ( struct sha256_context ),
|
||||
.blocksize = sizeof ( union sha256_block ),
|
||||
.digestsize = sizeof ( struct sha256_digest ),
|
||||
.init = sha256_init,
|
||||
.update = sha256_update,
|
||||
.final = sha256_final,
|
||||
};
|
||||
|
||||
/** "sha256" object identifier */
|
||||
static uint8_t oid_sha256[] = { ASN1_OID_SHA256 };
|
||||
|
||||
/** "sha256" OID-identified algorithm */
|
||||
struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm = {
|
||||
.name = "sha256",
|
||||
.digest = &sha256_algorithm,
|
||||
.oid = ASN1_OID_CURSOR ( oid_sha256 ),
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user