diff --git a/genprotimg/boot/.gitignore b/genprotimg/boot/.gitignore new file mode 100644 index 00000000..0a8eae62 --- /dev/null +++ b/genprotimg/boot/.gitignore @@ -0,0 +1,3 @@ +*.elf +*.bin +*.d diff --git a/genprotimg/boot/Makefile b/genprotimg/boot/Makefile new file mode 100644 index 00000000..271a8078 --- /dev/null +++ b/genprotimg/boot/Makefile @@ -0,0 +1,83 @@ +# Common definitions +include ../../common.mak + +ZIPL_DIR := $(rootdir)/zipl +ZIPL_BOOT_DIR := $(ZIPL_DIR)/boot + +INCLUDE_PATHS := $(ZIPL_BOOT_DIR) $(ZIPL_DIR)/include $(rootdir)/include +INCLUDE_PARMS := $(addprefix -I,$(INCLUDE_PATHS)) + +ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \ + $(INCLUDE_PARMS) \ + -DENABLE_SCLP_ASCII=1 \ + -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \ + -fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \ + -fno-delete-null-pointer-checks \ + -fexec-charset=IBM1047 -m64 -mpacked-stack \ + -mstack-size=4096 -mstack-guard=128 -msoft-float \ + -Wall -Wformat-security -Wextra -Werror + +FILES := stage3a.bin stage3b.bin + +ZIPL_SRCS_C := libc.c ebcdic.c ebcdic_conv.c sclp.c +ZIPL_SRCS_ASM := entry.S + +ZIPL_OBJS_C := $(ZIPL_SRCS_C:%.c=%.o) +ZIPL_OBJS_ASM := $(ZIPL_SRCS_ASM:%.S=%.o) +ZIPL_OBJS := $(ZIPL_OBJS_C) $(ZIPL_OBJS_ASM) + + +all: $(FILES) + +# Prevent make from using some default rules... +%: %.S + +%.o: %.S Makefile + $(CC) $(ALL_CFLAGS) -c -o $@ $< + +%.o: %.c Makefile + $(CC) $(ALL_CFLAGS) -c -o $@ $< + + +# Special rules for zipl object files +$(ZIPL_OBJS_C): %.o : $(ZIPL_BOOT_DIR)/%.c + $(CC) $(ALL_CFLAGS) -c -o $@ $< + +$(ZIPL_OBJS_ASM): %.o : $(ZIPL_BOOT_DIR)/%.S + $(CC) $(ALL_CFLAGS) -c -o $@ $< + +dependencies_zipl_c := $(ZIPL_SRCS_C:%.c=.%.o.d) + +$(dependencies_zipl_c): .%.o.d : $(ZIPL_BOOT_DIR)/%.c + $(CC_SILENT) -MM $(ALL_CPPFLAGS) $(ALL_CFLAGS) $< > $@ + +ifneq ($(MAKECMDGOALS),clean) +-include $(dependencies_zipl_c) +endif + + +stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS) +stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS) + +%.elf: %.o + case $* in \ + stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \ + stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \ + esac; \ + $(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@ + @chmod a-x $@ + +%.bin: %.elf + $(OBJCOPY) -O binary \ + --only-section=.text* \ + --only-section=.ex_table* \ + --only-section=.fixup* \ + --only-section=.data* \ + --only-section=.rodata* \ + $< $@ + @chmod a-x $@ + +clean: + rm -f *.o *.elf *.bin *.map .*.d + +.PHONY: all clean diff --git a/genprotimg/boot/common_memory_layout.h b/genprotimg/boot/common_memory_layout.h new file mode 100644 index 00000000..4750191c --- /dev/null +++ b/genprotimg/boot/common_memory_layout.h @@ -0,0 +1,25 @@ +/* + * Common memory layout for stage3a and stage3b bootloader. + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef COMMON_MEMORY_LAYOUT_H +#define COMMON_MEMORY_LAYOUT_H + +#include "boot/loaders_layout.h" + +#define STACK_ADDRESS STAGE3_STACK_ADDRESS +#define STACK_SIZE STAGE3_STACK_SIZE + +#define HEAP_ADDRESS STAGE3_HEAP_ADDRESS +#define HEAP_SIZE STAGE3_HEAP_SIZE + + +#ifndef __ASSEMBLER__ + +#endif /* __ASSEMBLER__ */ +#endif /* COMMON_MEMORY_LAYOUT_H */ diff --git a/genprotimg/boot/head.S b/genprotimg/boot/head.S new file mode 100644 index 00000000..8fae4604 --- /dev/null +++ b/genprotimg/boot/head.S @@ -0,0 +1,29 @@ +/* + * Entry code for stage 3a boot loader + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + + +#include "common_memory_layout.h" + +#include "boot/s390.h" +#include "boot/sigp.h" + +.section .text.start +.globl _start +_start: + /* Might be called after a diag308 so better set + * architecture and addressing mode + */ + lhi %r1, 1 + sigp %r1, %r0, SIGP_SET_ARCHITECTURE + sam64 + + /* Initialize stack */ + lgfi %r15, STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD + brasl %r14, initialize +.previous diff --git a/genprotimg/boot/stage3a.c b/genprotimg/boot/stage3a.c new file mode 100644 index 00000000..ae944d23 --- /dev/null +++ b/genprotimg/boot/stage3a.c @@ -0,0 +1,62 @@ +/* + * Main program for stage3a bootloader + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "libc.h" +#include "stage3a.h" + +#include "lib/zt_common.h" +#include "boot/s390.h" +#include "boot/ipl.h" +#include "sclp.h" +#include "error.h" + + +static volatile struct stage3a_args __section(".loader_parms") loader_parms; + +void __noreturn start(void) +{ + int rc; + volatile struct stage3a_args *args = &loader_parms; + /* calculate the IPIB memory address */ + struct ipl_parameter_block *ipib = (void *)((uint64_t)args + args->ipib_offs); + + /* Calculate the PV header memory address and set it and its + * size in the IPIB. This allows the PV header to be position + * independent. + */ + ipib->pv.pv_hdr_addr = (uint64_t)args + args->hdr_offs; + ipib->pv.pv_hdr_size = args->hdr_size; + + /* set up ASCII and line-mode */ + sclp_setup(SCLP_LINE_ASCII_INIT); + + /* test if Secure Execution Unpack facility is available */ + stfle(S390_lowcore.stfle_fac_list, + ARRAY_SIZE(S390_lowcore.stfle_fac_list)); + rc = test_facility(UNPACK_FACILITY); + if (rc == 0) + panic(ENOPV, "Secure unpack facility is not available\n"); + + rc = diag308(DIAG308_SET_PV, ipib); + if (rc != DIAG308_RC_OK) + panic(EPV, "Protected boot setup has failed: 0x%x\n", rc); + + rc = diag308(DIAG308_UNPACK_PV, 0x0); + if (rc != DIAG308_RC_OK) { + sclp_setup(SCLP_LINE_ASCII_INIT); + panic(EPV, "Protected boot has failed: 0x%x\n", rc); + } + + while (1) + ; +} + +void panic_notify(unsigned long UNUSED(rc)) +{ +} diff --git a/genprotimg/boot/stage3a.h b/genprotimg/boot/stage3a.h new file mode 100644 index 00000000..f362e866 --- /dev/null +++ b/genprotimg/boot/stage3a.h @@ -0,0 +1,34 @@ +/* + * Main program for stage3a bootloader. + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STAGE3A_H +#define STAGE3A_H + +#include "lib/zt_common.h" +#include "boot/loaders_layout.h" + +#define STAGE3A_INIT_ENTRY IMAGE_ENTRY +#define STAGE3A_ENTRY (STAGE3A_INIT_ENTRY + _AC(0x1000, UL)) +#define STAGE3A_LOAD_ADDRESS IMAGE_LOAD_ADDRESS + + +#ifndef __ASSEMBLER__ + +#include + +/* Must not have any padding */ +struct stage3a_args { + uint64_t hdr_offs; + uint64_t hdr_size; + uint64_t ipib_offs; +}; +STATIC_ASSERT(sizeof(struct stage3a_args) == 3 * 8) + +#endif /* __ASSEMBLER__ */ +#endif /* STAGE3A_H */ diff --git a/genprotimg/boot/stage3a.lds b/genprotimg/boot/stage3a.lds new file mode 100644 index 00000000..b6445cd2 --- /dev/null +++ b/genprotimg/boot/stage3a.lds @@ -0,0 +1,101 @@ +/* + * Memory layout for stage 3a + * ========================== + * + * General memory layout + * --------------------- + * + * 0x00000 - 0x01fff Lowcore + * 0x02000 - 0x05fff Memory allocation (heap) + * 0x0f000 - 0x0ffff Stack + * 0x10000 - 0x10012 Jump to the "actual" stage3a code + * 0x11000 - 0x12fff Stage3a code + arguments (offsets and lengths to the + * actual data: IPIB and UV header) + */ + +OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390") +OUTPUT_ARCH(s390:64-bit) + +ENTRY(_init) + +__heap_size__ = 0x4000; +__stack_size__ = 0x1000; + +SECTIONS +{ + . = 0x0; + + . = 0x2000; + __heap_start = .; + .heap : { + . = . + __heap_size__; + ASSERT(__heap_stop - __heap_start == __heap_size__, + "Heap section doesn't conform to the described memory layout"); + } + __heap_stop = .; + + . = 0xf000; + __stack_start = .; + .stack : { + . = . + __stack_size__; + ASSERT(__stack_end - __stack_start == __stack_size__, + "Stack section doesn't conform to the described memory layout"); + } + __stack_end = .; + + . = 0x10000; + __text_init_start = .; + .text : { + stage3a_init.o(.text.init) + __text_init_stop = ABSOLUTE(.); + /* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY', + * otherwise the text data could be overwritten by the original zipl stage3 + * boot loader */ + ASSERT(__text_init_stop - __text_init_start < 0x400, + "Text size must be smaller than 'PARMAREA - IMAGE_ENTRY'"); + . = 0x1000; + head.o(.text.start) + *(.text) + } + + .ex_table ALIGN(16) : { + __ex_table_start = .; + *(.ex_table) + __ex_table_stop = .; + } + + .bss ALIGN(16) : { + __bss_start = .; + *(.bss) + __bss_stop = .; + } + + .rodata ALIGN(16) : { + *(.rodata) + *(.rodata.*) + } + + .data ALIGN(16) : { + *(.data) + . = ALIGN(16); + /* The IPIB offset and the UV header offset and size will be + * saved in 'loader_parms' */ + __loader_parms_start = .; + KEEP(*(.loader_parms)); + __loader_parms_stop = .; + ASSERT(__loader_parms_stop - __loader_parms_start == 3 * 8, + "Data size must be equal to 'sizeof(struct stage3a_args)'"); + ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout"); + } + + /* List this explicitly as otherwise .note.gnu.build-id will be + * put at 0x0 */ + .notes : { + *(.note.*) + } + + /* Sections to be discarded */ + /DISCARD/ : { + *(.eh_frame) + } +} diff --git a/genprotimg/boot/stage3a_init.S b/genprotimg/boot/stage3a_init.S new file mode 100644 index 00000000..87c8d754 --- /dev/null +++ b/genprotimg/boot/stage3a_init.S @@ -0,0 +1,26 @@ +/* + * Entry code for stage 3a boot loader + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "stage3a.h" +#include "boot/sigp.h" + +.section .text.init +.globl _init +_init: + /* set architecture and switch to 64bit */ + lhi %r1, 1 + sigp %r1, %r0, SIGP_SET_ARCHITECTURE + sam64 + /* The original stage3 boot loader will try to store the + * kernel command line and the address and size of the + * ramdisk. Simply ignore this by starting at 0x11000. + */ + lgfi %r1, STAGE3A_ENTRY + br %r1 +.previous diff --git a/genprotimg/boot/stage3b.c b/genprotimg/boot/stage3b.c new file mode 100644 index 00000000..b1a7fbe4 --- /dev/null +++ b/genprotimg/boot/stage3b.c @@ -0,0 +1,77 @@ +/* + * Main program for stage3b bootloader + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "libc.h" +#include "stage3b.h" + +#include "lib/zt_common.h" +#include "boot/s390.h" +#include "boot/linux_layout.h" +#include "boot/loaders_layout.h" +#include "sclp.h" +#include "error.h" + + +static volatile struct stage3b_args __section(".loader_parms") loader_parms; + +static inline void __noreturn load_psw(struct psw_t psw) +{ + asm volatile("lpswe %0" : : "Q"(psw) : "cc"); + + while (1) + ; +} + +void __noreturn start(void) +{ + volatile struct stage3b_args *args = &loader_parms; + volatile struct memblob *kernel = &args->kernel; + volatile struct memblob *cmdline = &args->cmdline; + volatile struct memblob *initrd = &args->initrd; + volatile struct psw_t psw = args->psw; + + /* set up ASCII and line-mode */ + sclp_setup(SCLP_LINE_ASCII_INIT); + + if (kernel->size < IMAGE_LOAD_ADDRESS) + panic(EINTERNAL, "Invalid kernel\n"); + + if (cmdline->size > COMMAND_LINE_SIZE) + panic(EINTERNAL, "Command line is too large\n"); + + /* move the kernel and cut the kernel header */ + memmove((void *)IMAGE_LOAD_ADDRESS, + (void *)(kernel->src + IMAGE_LOAD_ADDRESS), + kernel->size - IMAGE_LOAD_ADDRESS); + + /* move the kernel cmdline */ + memmove((void *)COMMAND_LINE, + (void *)cmdline->src, + cmdline->size); + /* the initrd does not need to be moved */ + + if (initrd->size != 0) { + /* copy initrd start address and size into new kernel space */ + *(unsigned long long *)INITRD_START = initrd->src; + *(unsigned long long *)INITRD_SIZE = initrd->size; + } + + /* disable ASCII and line-mode */ + sclp_setup(SCLP_DISABLE); + + /* use lpswe instead of diag308 as a I/O subsystem reset is not + * needed as this was already done by the diag308 subcode 10 call + * in stage3a + */ + load_psw(psw); +} + +void panic_notify(unsigned long UNUSED(rc)) +{ +} diff --git a/genprotimg/boot/stage3b.h b/genprotimg/boot/stage3b.h new file mode 100644 index 00000000..6325d27e --- /dev/null +++ b/genprotimg/boot/stage3b.h @@ -0,0 +1,38 @@ +/* + * Main program for stage3b bootloader + * + * Copyright IBM Corp. 2020 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STAGE3B_H +#define STAGE3B_H + +#include "lib/zt_common.h" + + +#ifndef __ASSEMBLER__ + +#include + +#include "boot/s390.h" + +/* Must not have any padding included */ +struct memblob { + uint64_t src; + uint64_t size; +}; +STATIC_ASSERT(sizeof(struct memblob) == 2 * 8) + +/* Must not have any padding included */ +struct stage3b_args { + struct memblob kernel; + struct memblob cmdline; + struct memblob initrd; + struct psw_t psw; +}; +STATIC_ASSERT(sizeof(struct stage3b_args) == 3 * sizeof(struct memblob) + 16) +#endif /* __ASSEMBLER__ */ +#endif /* STAGE3B_H */ diff --git a/genprotimg/boot/stage3b.lds b/genprotimg/boot/stage3b.lds new file mode 100644 index 00000000..98122ea0 --- /dev/null +++ b/genprotimg/boot/stage3b.lds @@ -0,0 +1,87 @@ +/* + * Memory layout for stage 3b + * ========================== + * + * General memory layout + * --------------------- + * + * 0x00000 - 0x01fff Lowcore + * 0x02000 - 0x05fff Memory allocation (heap) + * 0x0a000 - 0x0efff Stage3b code + * 0x0f000 - 0x0ffff Stack + */ + +OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390") +OUTPUT_ARCH(s390:64-bit) + +ENTRY(_start) + +__heap_size__ = 0x4000; +__stack_size__ = 0x1000; + +SECTIONS +{ + . = 0x0; + + . = 0x2000; + __heap_start = .; + .heap : { + . = . + __heap_size__; + ASSERT(__heap_stop - __heap_start == __heap_size__, + "Heap section doesn't conform to the described memory layout"); + } + __heap_stop = .; + + . = 0xa000; + .text : { + head.o(.text.start) + *(.text) + } + + .ex_table ALIGN(16) : { + __ex_table_start = .; + *(.ex_table) + __ex_table_stop = .; + } + + .bss ALIGN(16) : { + __bss_start = .; + *(.bss) + __bss_stop = .; + } + + .rodata ALIGN(16) : { + *(.rodata) + *(.rodata.*) + } + + .data ALIGN(16) : { + *(.data) + . = ALIGN(16); + __loader_parms_start = .; + KEEP(*(.loader_parms)); + __loader_parms_end = .; + ASSERT(__loader_parms_end - __loader_parms_start == 3 * 16 + 16, + "Data size must be equal to 'sizeof(struct stage3b_args)'"); + } + + . = 0xf000; + __stack_start = .; + .stack : { + . = . + __stack_size__; + ASSERT(__stack_end - __stack_start == __stack_size__, + "Stack section doesn't conform to the described memory layout"); + } + __stack_end = .; + + /* List this explicitly as otherwise .note.gnu.build-id will be + * put at 0x0 */ + .notes : { + *(.note.*) + } + + /* Sections to be discarded */ + /DISCARD/ : { + *(.eh_frame) + } +} diff --git a/include/boot/ipl.h b/include/boot/ipl.h index ae5be195..ab3f7c4f 100644 --- a/include/boot/ipl.h +++ b/include/boot/ipl.h @@ -89,6 +89,30 @@ struct ipl_pb0_ccw { uint8_t reserved5[8]; } __packed; +/* Structure must not have any padding */ +struct ipl_pb0_pv_comp { + uint64_t tweak_pref; + uint64_t addr; + uint64_t len; +}; +STATIC_ASSERT(sizeof(struct ipl_pb0_pv_comp) == 3 * 8) + +/* IPL Parameter Block 0 for PV */ +struct ipl_pb0_pv { + uint32_t len; + uint8_t pbt; + uint8_t reserved1[3]; + uint8_t loadparm[8]; + uint8_t reserved2[84]; + uint8_t reserved3[3]; + uint8_t version; + uint8_t reserved4[4]; + uint32_t num_comp; + uint64_t pv_hdr_addr; + uint64_t pv_hdr_size; + struct ipl_pb0_pv_comp components[]; +} __packed; + struct ipl_parameter_block { struct ipl_pl_hdr hdr; union { @@ -96,6 +120,7 @@ struct ipl_parameter_block { struct ipl_pb0_common common; struct ipl_pb0_fcp fcp; struct ipl_pb0_ccw ccw; + struct ipl_pb0_pv pv; char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)]; }; } __packed __aligned(PAGE_SIZE); diff --git a/include/boot/s390.h b/include/boot/s390.h index af842e1c..00eb68e6 100644 --- a/include/boot/s390.h +++ b/include/boot/s390.h @@ -18,6 +18,12 @@ #define PAGE_SIZE _AC(4096, UL) +/* Minimum size of a stack frame in bytes */ +#define STACK_FRAME_OVERHEAD _AC(160, U) + +/* Facilities */ +#define UNPACK_FACILITY _AC(161, U) + #ifndef __ASSEMBLER__ @@ -262,11 +268,17 @@ static __always_inline void __ctl_set_bit(unsigned int cr, unsigned int bit) * DIAG 308 support */ enum diag308_subcode { - DIAG308_REL_HSA = 2, - DIAG308_IPL = 3, - DIAG308_DUMP = 4, - DIAG308_SET = 5, - DIAG308_STORE = 6, + DIAG308_REL_HSA = 2, + DIAG308_IPL = 3, + DIAG308_DUMP = 4, + DIAG308_SET = 5, + DIAG308_STORE = 6, + DIAG308_SET_PV = 8, + DIAG308_UNPACK_PV = 10, +}; + +enum diag308_rc { + DIAG308_RC_OK = 0x0001, }; static __always_inline unsigned long diag308(unsigned long subcode, void *addr) diff --git a/zipl/boot/error.h b/zipl/boot/error.h index 715973ec..63eae4bd 100644 --- a/zipl/boot/error.h +++ b/zipl/boot/error.h @@ -71,4 +71,10 @@ #define ENOTIME 0x00004605 /* The zipl time stamps do not match */ #define ENOMSS 0x00004606 /* Could not enable MSS */ +/* + * PV error codes + */ +#define ENOPV 0x00004607 /* No support for PV */ +#define EPV 0x00004608 /* PV error */ + #endif /* ERROR_H */