From 1caf170df9bac49bb198c424aee45f5ecced076a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 13 Jun 2017 14:46:18 +0200 Subject: s390/mm: provide base_asce_alloc() / base_asce_free() helper functions Provide base_asce_alloc() and base_asce_free() helper functions which can be used to allocate an ASCE and all required region, segment and page tables required to access memory regions of the virtual kernel address space. Both, the ASCE and all tables, do not use any features that correspond to e.g. enhanced DAT features. This is required for some I/O functions that pass an ASCE, like e.g. some service call requests, but which may not use any enhanced features. Acked-by: Peter Oberparleiter Acked-by: Janosch Frank Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/pgalloc.h | 3 + arch/s390/mm/pgalloc.c | 293 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 295 insertions(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index c7b4333d1de0..f0f9bcf94c03 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -151,4 +151,7 @@ void vmem_map_init(void); void *vmem_crst_alloc(unsigned long val); pte_t *vmem_pte_alloc(void); +unsigned long base_asce_alloc(unsigned long addr, unsigned long num_pages); +void base_asce_free(unsigned long asce); + #endif /* _S390_PGALLOC_H */ diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index cb364153c43c..562f72955956 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -6,8 +6,9 @@ * Author(s): Martin Schwidefsky */ -#include #include +#include +#include #include #include #include @@ -366,3 +367,293 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table) if ((*batch)->nr == MAX_TABLE_BATCH) tlb_flush_mmu(tlb); } + +/* + * Base infrastructure required to generate basic asces, region, segment, + * and page tables that do not make use of enhanced features like EDAT1. + */ + +static struct kmem_cache *base_pgt_cache; + +static unsigned long base_pgt_alloc(void) +{ + u64 *table; + + table = kmem_cache_alloc(base_pgt_cache, GFP_KERNEL); + if (table) + memset64(table, _PAGE_INVALID, PTRS_PER_PTE); + return (unsigned long) table; +} + +static void base_pgt_free(unsigned long table) +{ + kmem_cache_free(base_pgt_cache, (void *) table); +} + +static unsigned long base_crst_alloc(unsigned long val) +{ + unsigned long table; + + table = __get_free_pages(GFP_KERNEL, CRST_ALLOC_ORDER); + if (table) + crst_table_init((unsigned long *)table, val); + return table; +} + +static void base_crst_free(unsigned long table) +{ + free_pages(table, CRST_ALLOC_ORDER); +} + +#define BASE_ADDR_END_FUNC(NAME, SIZE) \ +static inline unsigned long base_##NAME##_addr_end(unsigned long addr, \ + unsigned long end) \ +{ \ + unsigned long next = (addr + (SIZE)) & ~((SIZE) - 1); \ + \ + return (next - 1) < (end - 1) ? next : end; \ +} + +BASE_ADDR_END_FUNC(page, _PAGE_SIZE) +BASE_ADDR_END_FUNC(segment, _SEGMENT_SIZE) +BASE_ADDR_END_FUNC(region3, _REGION3_SIZE) +BASE_ADDR_END_FUNC(region2, _REGION2_SIZE) +BASE_ADDR_END_FUNC(region1, _REGION1_SIZE) + +static inline unsigned long base_lra(unsigned long address) +{ + unsigned long real; + + asm volatile( + " lra %0,0(%1)\n" + : "=d" (real) : "a" (address) : "cc"); + return real; +} + +static int base_page_walk(unsigned long origin, unsigned long addr, + unsigned long end, int alloc) +{ + unsigned long *pte, next; + + if (!alloc) + return 0; + pte = (unsigned long *) origin; + pte += (addr & _PAGE_INDEX) >> _PAGE_SHIFT; + do { + next = base_page_addr_end(addr, end); + *pte = base_lra(addr); + } while (pte++, addr = next, addr < end); + return 0; +} + +static int base_segment_walk(unsigned long origin, unsigned long addr, + unsigned long end, int alloc) +{ + unsigned long *ste, next, table; + int rc; + + ste = (unsigned long *) origin; + ste += (addr & _SEGMENT_INDEX) >> _SEGMENT_SHIFT; + do { + next = base_segment_addr_end(addr, end); + if (*ste & _SEGMENT_ENTRY_INVALID) { + if (!alloc) + continue; + table = base_pgt_alloc(); + if (!table) + return -ENOMEM; + *ste = table | _SEGMENT_ENTRY; + } + table = *ste & _SEGMENT_ENTRY_ORIGIN; + rc = base_page_walk(table, addr, next, alloc); + if (rc) + return rc; + if (!alloc) + base_pgt_free(table); + cond_resched(); + } while (ste++, addr = next, addr < end); + return 0; +} + +static int base_region3_walk(unsigned long origin, unsigned long addr, + unsigned long end, int alloc) +{ + unsigned long *rtte, next, table; + int rc; + + rtte = (unsigned long *) origin; + rtte += (addr & _REGION3_INDEX) >> _REGION3_SHIFT; + do { + next = base_region3_addr_end(addr, end); + if (*rtte & _REGION_ENTRY_INVALID) { + if (!alloc) + continue; + table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY); + if (!table) + return -ENOMEM; + *rtte = table | _REGION3_ENTRY; + } + table = *rtte & _REGION_ENTRY_ORIGIN; + rc = base_segment_walk(table, addr, next, alloc); + if (rc) + return rc; + if (!alloc) + base_crst_free(table); + } while (rtte++, addr = next, addr < end); + return 0; +} + +static int base_region2_walk(unsigned long origin, unsigned long addr, + unsigned long end, int alloc) +{ + unsigned long *rste, next, table; + int rc; + + rste = (unsigned long *) origin; + rste += (addr & _REGION2_INDEX) >> _REGION2_SHIFT; + do { + next = base_region2_addr_end(addr, end); + if (*rste & _REGION_ENTRY_INVALID) { + if (!alloc) + continue; + table = base_crst_alloc(_REGION3_ENTRY_EMPTY); + if (!table) + return -ENOMEM; + *rste = table | _REGION2_ENTRY; + } + table = *rste & _REGION_ENTRY_ORIGIN; + rc = base_region3_walk(table, addr, next, alloc); + if (rc) + return rc; + if (!alloc) + base_crst_free(table); + } while (rste++, addr = next, addr < end); + return 0; +} + +static int base_region1_walk(unsigned long origin, unsigned long addr, + unsigned long end, int alloc) +{ + unsigned long *rfte, next, table; + int rc; + + rfte = (unsigned long *) origin; + rfte += (addr & _REGION1_INDEX) >> _REGION1_SHIFT; + do { + next = base_region1_addr_end(addr, end); + if (*rfte & _REGION_ENTRY_INVALID) { + if (!alloc) + continue; + table = base_crst_alloc(_REGION2_ENTRY_EMPTY); + if (!table) + return -ENOMEM; + *rfte = table | _REGION1_ENTRY; + } + table = *rfte & _REGION_ENTRY_ORIGIN; + rc = base_region2_walk(table, addr, next, alloc); + if (rc) + return rc; + if (!alloc) + base_crst_free(table); + } while (rfte++, addr = next, addr < end); + return 0; +} + +/** + * base_asce_free - free asce and tables returned from base_asce_alloc() + * @asce: asce to be freed + * + * Frees all region, segment, and page tables that were allocated with a + * corresponding base_asce_alloc() call. + */ +void base_asce_free(unsigned long asce) +{ + unsigned long table = asce & _ASCE_ORIGIN; + + if (!asce) + return; + switch (asce & _ASCE_TYPE_MASK) { + case _ASCE_TYPE_SEGMENT: + base_segment_walk(table, 0, _REGION3_SIZE, 0); + break; + case _ASCE_TYPE_REGION3: + base_region3_walk(table, 0, _REGION2_SIZE, 0); + break; + case _ASCE_TYPE_REGION2: + base_region2_walk(table, 0, _REGION1_SIZE, 0); + break; + case _ASCE_TYPE_REGION1: + base_region1_walk(table, 0, -_PAGE_SIZE, 0); + break; + } + base_crst_free(table); +} + +static int base_pgt_cache_init(void) +{ + static DEFINE_MUTEX(base_pgt_cache_mutex); + unsigned long sz = _PAGE_TABLE_SIZE; + + if (base_pgt_cache) + return 0; + mutex_lock(&base_pgt_cache_mutex); + if (!base_pgt_cache) + base_pgt_cache = kmem_cache_create("base_pgt", sz, sz, 0, NULL); + mutex_unlock(&base_pgt_cache_mutex); + return base_pgt_cache ? 0 : -ENOMEM; +} + +/** + * base_asce_alloc - create kernel mapping without enhanced DAT features + * @addr: virtual start address of kernel mapping + * @num_pages: number of consecutive pages + * + * Generate an asce, including all required region, segment and page tables, + * that can be used to access the virtual kernel mapping. The difference is + * that the returned asce does not make use of any enhanced DAT features like + * e.g. large pages. This is required for some I/O functions that pass an + * asce, like e.g. some service call requests. + * + * Note: the returned asce may NEVER be attached to any cpu. It may only be + * used for I/O requests. tlb entries that might result because the + * asce was attached to a cpu won't be cleared. + */ +unsigned long base_asce_alloc(unsigned long addr, unsigned long num_pages) +{ + unsigned long asce, table, end; + int rc; + + if (base_pgt_cache_init()) + return 0; + end = addr + num_pages * PAGE_SIZE; + if (end <= _REGION3_SIZE) { + table = base_crst_alloc(_SEGMENT_ENTRY_EMPTY); + if (!table) + return 0; + rc = base_segment_walk(table, addr, end, 1); + asce = table | _ASCE_TYPE_SEGMENT | _ASCE_TABLE_LENGTH; + } else if (end <= _REGION2_SIZE) { + table = base_crst_alloc(_REGION3_ENTRY_EMPTY); + if (!table) + return 0; + rc = base_region3_walk(table, addr, end, 1); + asce = table | _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; + } else if (end <= _REGION1_SIZE) { + table = base_crst_alloc(_REGION2_ENTRY_EMPTY); + if (!table) + return 0; + rc = base_region2_walk(table, addr, end, 1); + asce = table | _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH; + } else { + table = base_crst_alloc(_REGION1_ENTRY_EMPTY); + if (!table) + return 0; + rc = base_region1_walk(table, addr, end, 1); + asce = table | _ASCE_TYPE_REGION1 | _ASCE_TABLE_LENGTH; + } + if (rc) { + base_asce_free(asce); + asce = 0; + } + return asce; +} -- cgit v1.2.3-59-g8ed1b From ddc1c9453550eabd6284021b167f708982df3ca9 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 19 Dec 2017 16:18:38 +0100 Subject: s390/dasd: configurable IFCC handling Make the behavior in case of constant IFCC/CCC errors configurable. Add a sysfs attribute to switch between path disabled after threshold exceeded (default) and message only. Reviewed-by: Jan Hoeppner Reviewed-by: Sebastian Ott Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- arch/s390/include/uapi/asm/dasd.h | 38 +++++++++++++++++---------------- drivers/s390/block/dasd_3990_erp.c | 17 +++++++++++++-- drivers/s390/block/dasd_devmap.c | 43 +++++++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 21 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/uapi/asm/dasd.h b/arch/s390/include/uapi/asm/dasd.h index 451c601406b6..832be5c2584f 100644 --- a/arch/s390/include/uapi/asm/dasd.h +++ b/arch/s390/include/uapi/asm/dasd.h @@ -68,25 +68,27 @@ typedef struct dasd_information2_t { #define DASD_FORMAT_CDL 2 /* * values to be used for dasd_information_t.features - * 0x00: default features - * 0x01: readonly (ro) - * 0x02: use diag discipline (diag) - * 0x04: set the device initially online (internal use only) - * 0x08: enable ERP related logging - * 0x10: allow I/O to fail on lost paths - * 0x20: allow I/O to fail when a lock was stolen - * 0x40: give access to raw eckd data - * 0x80: enable discard support + * 0x100: default features + * 0x001: readonly (ro) + * 0x002: use diag discipline (diag) + * 0x004: set the device initially online (internal use only) + * 0x008: enable ERP related logging + * 0x010: allow I/O to fail on lost paths + * 0x020: allow I/O to fail when a lock was stolen + * 0x040: give access to raw eckd data + * 0x080: enable discard support + * 0x100: enable autodisable for IFCC errors (default) */ -#define DASD_FEATURE_DEFAULT 0x00 -#define DASD_FEATURE_READONLY 0x01 -#define DASD_FEATURE_USEDIAG 0x02 -#define DASD_FEATURE_INITIAL_ONLINE 0x04 -#define DASD_FEATURE_ERPLOG 0x08 -#define DASD_FEATURE_FAILFAST 0x10 -#define DASD_FEATURE_FAILONSLCK 0x20 -#define DASD_FEATURE_USERAW 0x40 -#define DASD_FEATURE_DISCARD 0x80 +#define DASD_FEATURE_READONLY 0x001 +#define DASD_FEATURE_USEDIAG 0x002 +#define DASD_FEATURE_INITIAL_ONLINE 0x004 +#define DASD_FEATURE_ERPLOG 0x008 +#define DASD_FEATURE_FAILFAST 0x010 +#define DASD_FEATURE_FAILONSLCK 0x020 +#define DASD_FEATURE_USERAW 0x040 +#define DASD_FEATURE_DISCARD 0x080 +#define DASD_FEATURE_PATH_AUTODISABLE 0x100 +#define DASD_FEATURE_DEFAULT DASD_FEATURE_PATH_AUTODISABLE #define DASD_PARTN_BITS 2 diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index ee14d8e45c97..ee73b0607e47 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2214,15 +2214,28 @@ static void dasd_3990_erp_disable_path(struct dasd_device *device, __u8 lpum) { int pos = pathmask_to_pos(lpum); + if (!(device->features & DASD_FEATURE_PATH_AUTODISABLE)) { + dev_err(&device->cdev->dev, + "Path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n", + device->path[pos].cssid, device->path[pos].chpid, lpum); + goto out; + } + /* no remaining path, cannot disable */ - if (!(dasd_path_get_opm(device) & ~lpum)) - return; + if (!(dasd_path_get_opm(device) & ~lpum)) { + dev_err(&device->cdev->dev, + "Last path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n", + device->path[pos].cssid, device->path[pos].chpid, lpum); + goto out; + } dev_err(&device->cdev->dev, "Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n", device->path[pos].cssid, device->path[pos].chpid, lpum); dasd_path_remove_opm(device, lpum); dasd_path_add_ifccpm(device, lpum); + +out: device->path[pos].errorclk = 0; atomic_set(&device->path[pos].error_count, 0); } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index e7cd28ff1984..b9ebb565ee2c 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -1550,9 +1550,49 @@ dasd_path_threshold_store(struct device *dev, struct device_attribute *attr, dasd_put_device(device); return count; } - static DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show, dasd_path_threshold_store); + +/* + * configure if path is disabled after IFCC/CCC error threshold is + * exceeded + */ +static ssize_t +dasd_path_autodisable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dasd_devmap *devmap; + int flag; + + devmap = dasd_find_busid(dev_name(dev)); + if (!IS_ERR(devmap)) + flag = (devmap->features & DASD_FEATURE_PATH_AUTODISABLE) != 0; + else + flag = (DASD_FEATURE_DEFAULT & + DASD_FEATURE_PATH_AUTODISABLE) != 0; + return snprintf(buf, PAGE_SIZE, flag ? "1\n" : "0\n"); +} + +static ssize_t +dasd_path_autodisable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int val; + int rc; + + if (kstrtouint(buf, 0, &val) || val > 1) + return -EINVAL; + + rc = dasd_set_feature(to_ccwdev(dev), + DASD_FEATURE_PATH_AUTODISABLE, val); + + return rc ? : count; +} + +static DEVICE_ATTR(path_autodisable, 0644, + dasd_path_autodisable_show, + dasd_path_autodisable_store); /* * interval for IFCC/CCC checks * meaning time with no IFCC/CCC error before the error counter @@ -1623,6 +1663,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_host_access_count.attr, &dev_attr_path_masks.attr, &dev_attr_path_threshold.attr, + &dev_attr_path_autodisable.attr, &dev_attr_path_interval.attr, &dev_attr_path_reset.attr, &dev_attr_hpf.attr, -- cgit v1.2.3-59-g8ed1b From b35fe61df4bf10c7e164a416ff8241e42f3991aa Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 22 Feb 2018 13:14:16 +0100 Subject: s390: fix comment for scsw_cmd_is_valid_sctl This function is checking for the suspend control, not the function control. Signed-off-by: Cornelia Huck Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/scsw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/scsw.h b/arch/s390/include/asm/scsw.h index 79b7ffa91832..c00f7b031628 100644 --- a/arch/s390/include/asm/scsw.h +++ b/arch/s390/include/asm/scsw.h @@ -390,10 +390,10 @@ static inline int scsw_cmd_is_valid_key(union scsw *scsw) } /** - * scsw_cmd_is_valid_sctl - check fctl field validity + * scsw_cmd_is_valid_sctl - check sctl field validity * @scsw: pointer to scsw * - * Return non-zero if the fctl field of the specified command mode scsw is + * Return non-zero if the sctl field of the specified command mode scsw is * valid, zero otherwise. */ static inline int scsw_cmd_is_valid_sctl(union scsw *scsw) -- cgit v1.2.3-59-g8ed1b From 3ad6b250130de368066c5d6d7ebfdc328f655118 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 20 Feb 2018 11:12:30 +0100 Subject: s390/decompressor: discard __ex_table section Exception table (__ex_table section) is not used during the decompressor phase and could be discarded to save the memory. It is currently generated due to sclp_service_call function (sclp_early_core.c). An assumption is that decompressor usage of sclp_service_call via sclp_early_printk should never trigger exceptions. Signed-off-by: Vasily Gorbik Acked-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/boot/compressed/vmlinux.lds.S | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/s390') diff --git a/arch/s390/boot/compressed/vmlinux.lds.S b/arch/s390/boot/compressed/vmlinux.lds.S index 8150132b144f..d43c2db12d30 100644 --- a/arch/s390/boot/compressed/vmlinux.lds.S +++ b/arch/s390/boot/compressed/vmlinux.lds.S @@ -52,6 +52,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { *(.eh_frame) + *(__ex_table) *(*__ksymtab*) } } -- cgit v1.2.3-59-g8ed1b From 320d9555cb9d2f42cf933c7f59468998933f6cc7 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 20 Feb 2018 13:28:33 +0100 Subject: s390: unify linker symbols usage Common code defines linker symbols which denote sections start/end in a form of char []. Referencing those symbols as _symbol or &_symbol yields the same result, but "_symbol" form is more widespread across newly written code. Convert s390 specific code to this style. Also removes unused _text symbol definition in boot/compressed/misc.c. Signed-off-by: Vasily Gorbik Acked-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/boot/compressed/misc.c | 10 +++++----- arch/s390/kernel/early.c | 2 +- arch/s390/kernel/setup.c | 20 ++++++++++---------- arch/s390/kernel/suspend.c | 4 ++-- arch/s390/mm/dump_pagetables.c | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index cecf38b9ec82..63838a17e56a 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -27,8 +27,8 @@ /* Symbols defined by linker scripts */ extern char input_data[]; extern int input_len; -extern char _text, _end; -extern char _bss, _ebss; +extern char _end[]; +extern char _bss[], _ebss[]; static void error(char *m); @@ -144,7 +144,7 @@ unsigned long decompress_kernel(void) { void *output, *kernel_end; - output = (void *) ALIGN((unsigned long) &_end + HEAP_SIZE, PAGE_SIZE); + output = (void *) ALIGN((unsigned long) _end + HEAP_SIZE, PAGE_SIZE); kernel_end = output + SZ__bss_start; check_ipl_parmblock((void *) 0, (unsigned long) kernel_end); @@ -166,8 +166,8 @@ unsigned long decompress_kernel(void) * Clear bss section. free_mem_ptr and free_mem_end_ptr need to be * initialized afterwards since they reside in bss. */ - memset(&_bss, 0, &_ebss - &_bss); - free_mem_ptr = (unsigned long) &_end; + memset(_bss, 0, _ebss - _bss); + free_mem_ptr = (unsigned long) _end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index ac707a9f729e..53d089fc4501 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -67,7 +67,7 @@ static noinline __init void init_kernel_storage_key(void) #if PAGE_DEFAULT_KEY unsigned long end_pfn, init_pfn; - end_pfn = PFN_UP(__pa(&_end)); + end_pfn = PFN_UP(__pa(_end)); for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) page_set_storage_key(init_pfn << PAGE_SHIFT, diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index a6a91f01a17a..70ed7c72ab59 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -413,12 +413,12 @@ static void __init setup_resources(void) struct memblock_region *reg; int j; - code_resource.start = (unsigned long) &_text; - code_resource.end = (unsigned long) &_etext - 1; - data_resource.start = (unsigned long) &_etext; - data_resource.end = (unsigned long) &_edata - 1; - bss_resource.start = (unsigned long) &__bss_start; - bss_resource.end = (unsigned long) &__bss_stop - 1; + code_resource.start = (unsigned long) _text; + code_resource.end = (unsigned long) _etext - 1; + data_resource.start = (unsigned long) _etext; + data_resource.end = (unsigned long) _edata - 1; + bss_resource.start = (unsigned long) __bss_start; + bss_resource.end = (unsigned long) __bss_stop - 1; for_each_memblock(memory, reg) { res = memblock_virt_alloc(sizeof(*res), 8); @@ -667,7 +667,7 @@ static void __init check_initrd(void) */ static void __init reserve_kernel(void) { - unsigned long start_pfn = PFN_UP(__pa(&_end)); + unsigned long start_pfn = PFN_UP(__pa(_end)); #ifdef CONFIG_DMA_API_DEBUG /* @@ -888,9 +888,9 @@ void __init setup_arch(char **cmdline_p) /* Is init_mm really needed? */ init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; parse_early_param(); #ifdef CONFIG_CRASH_DUMP diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c index ce329c876d8c..75b7b307946e 100644 --- a/arch/s390/kernel/suspend.c +++ b/arch/s390/kernel/suspend.c @@ -153,8 +153,8 @@ int pfn_is_nosave(unsigned long pfn) { unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end)); - unsigned long end_rodata_pfn = PFN_DOWN(__pa(&__end_rodata)) - 1; - unsigned long stext_pfn = PFN_DOWN(__pa(&_stext)); + unsigned long end_rodata_pfn = PFN_DOWN(__pa(__end_rodata)) - 1; + unsigned long stext_pfn = PFN_DOWN(__pa(_stext)); /* Always save lowcore pages (LC protection might be enabled). */ if (pfn <= LC_PAGES) diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c index 507f23ba2034..7cdea2ec51e9 100644 --- a/arch/s390/mm/dump_pagetables.c +++ b/arch/s390/mm/dump_pagetables.c @@ -24,8 +24,8 @@ enum address_markers_idx { static struct addr_marker address_markers[] = { [IDENTITY_NR] = {0, "Identity Mapping"}, - [KERNEL_START_NR] = {(unsigned long)&_stext, "Kernel Image Start"}, - [KERNEL_END_NR] = {(unsigned long)&_end, "Kernel Image End"}, + [KERNEL_START_NR] = {(unsigned long)_stext, "Kernel Image Start"}, + [KERNEL_END_NR] = {(unsigned long)_end, "Kernel Image End"}, [VMEMMAP_NR] = {0, "vmemmap Area"}, [VMALLOC_NR] = {0, "vmalloc Area"}, [MODULES_NR] = {0, "Modules Area"}, -- cgit v1.2.3-59-g8ed1b From e0aa099c18e83ce6983270da36349e3d52179335 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 20 Feb 2018 11:31:34 +0100 Subject: s390: set bzImage as default image for packaging Even though s390 compressed kernel support has been introduced long ago, by default uncompressed kernel image is used by packaging targets like: "make rpm-pkg", "make deb-pkg" as well as "make image_name". At the same time "make install" would use compressed bzImage by default. To avoid ambiguity, set bzImage as default image for packaging. Signed-off-by: Vasily Gorbik Acked-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 2ced3239cb84..bd424f6a3c5b 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -47,9 +47,6 @@ cflags-$(CONFIG_MARCH_Z14_TUNE) += -mtune=z14 cflags-y += -Wa,-I$(srctree)/arch/$(ARCH)/include -#KBUILD_IMAGE is necessary for make rpm -KBUILD_IMAGE :=arch/s390/boot/image - # # Prevent tail-call optimizations, to get clearer backtraces: # @@ -126,6 +123,9 @@ tools := arch/s390/tools all: image bzImage +#KBUILD_IMAGE is necessary for packaging targets like rpm-pkg, deb-pkg... +KBUILD_IMAGE := $(boot)/bzImage + install: vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ -- cgit v1.2.3-59-g8ed1b From 5e725c570eaa405eb5b1a557e7c6831ac56c3088 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 26 Feb 2018 09:46:02 +0100 Subject: s390: fix typo in irb description s/sene/sense Signed-off-by: Julian Wiedmann Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/cio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h index dc84a0171bb3..847a04262b9c 100644 --- a/arch/s390/include/asm/cio.h +++ b/arch/s390/include/asm/cio.h @@ -227,7 +227,7 @@ struct esw_eadm { * a field is valid; a field not being valid is always passed as %0. * If a unit check occurred, @ecw may contain sense data; this is retrieved * by the common I/O layer itself if the device doesn't support concurrent - * sense (so that the device driver never needs to perform basic sene itself). + * sense (so that the device driver never needs to perform basic sense itself). * For unsolicited interrupts, the irb is passed as-is (expect for sense data, * if applicable). */ -- cgit v1.2.3-59-g8ed1b From 579f1a2883306518ff4bbd571009604dfa8ad7b0 Mon Sep 17 00:00:00 2001 From: Farhan Ali Date: Thu, 22 Feb 2018 11:22:24 -0500 Subject: s390/setup : enable display support for KVM guest The S390 architecture does not support any graphics hardware, but with the latest support for Virtio GPU in Linux and Virtio GPU emulation in QEMU, it's possible to enable graphics for S390 using the Virtio GPU device. To enable display we need to enable the Linux Virtual Terminal (VT) layer for S390. But the VT subsystem initializes quite early at boot so we need a dummy console driver till the Virtio GPU driver is initialized and we can run the framebuffer console. The framebuffer console over a Virtio GPU device can be run in combination with the serial SCLP console (default on S390). The SCLP console can still be accessed by management applications (eg: via Libvirt's virsh console). Signed-off-by: Farhan Ali Acked-by: Christian Borntraeger Reviewed-by: Thomas Huth Message-Id: Signed-off-by: Christian Borntraeger Acked-by: Greg Kroah-Hartman Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/setup.c | 2 ++ drivers/tty/Kconfig | 2 +- drivers/video/console/Kconfig | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 70ed7c72ab59..7b58a712f818 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -221,6 +221,8 @@ static void __init conmode_default(void) SET_CONSOLE_SCLP; #endif } + if (IS_ENABLED(CONFIG_VT) && IS_ENABLED(CONFIG_DUMMY_CONSOLE)) + conswitchp = &dummy_con; } #ifdef CONFIG_CRASH_DUMP diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index b811442c5ce6..5ca53facc2c8 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -11,7 +11,7 @@ if TTY config VT bool "Virtual terminal" if EXPERT - depends on !S390 && !UML + depends on !UML select INPUT default y ---help--- diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index d039a05cc978..b99e719d30c2 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -9,7 +9,7 @@ config VGA_CONSOLE depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !FRV && \ !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ - !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && HAS_IOMEM + !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && HAS_IOMEM && !S390 default y help Saying Y here will allow you to use Linux in text mode through a -- cgit v1.2.3-59-g8ed1b From c7260ca335a09fb186885c80bd6022318c10c541 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 1 Mar 2018 16:40:00 +0100 Subject: s390/crypto: Fix kernel crash on aes_s390 module remove. A kernel crash occurs when the aes_s390 kernel module is removed on machines < z14. This only happens on kernel version 4.15 and higher on machines not supporting MSA 8. The reason for the crash is a unconditional crypto_unregister_aead() invocation where no previous crypto_register_aead() had been called. The fix now remembers if there has been a successful registration and only then calls the unregister function upon kernel module remove. The code now crashing has been introduced with "bf7fa03 s390/crypto: add s390 platform specific aes gcm support." Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/crypto/aes_s390.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/s390') diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index d60798737d86..fa9b7dd1a513 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -1047,6 +1047,7 @@ static struct aead_alg gcm_aes_aead = { static struct crypto_alg *aes_s390_algs_ptr[5]; static int aes_s390_algs_num; +static struct aead_alg *aes_s390_aead_alg; static int aes_s390_register_alg(struct crypto_alg *alg) { @@ -1065,7 +1066,8 @@ static void aes_s390_fini(void) if (ctrblk) free_page((unsigned long) ctrblk); - crypto_unregister_aead(&gcm_aes_aead); + if (aes_s390_aead_alg) + crypto_unregister_aead(aes_s390_aead_alg); } static int __init aes_s390_init(void) @@ -1123,6 +1125,7 @@ static int __init aes_s390_init(void) ret = crypto_register_aead(&gcm_aes_aead); if (ret) goto out_err; + aes_s390_aead_alg = &gcm_aes_aead; } return 0; -- cgit v1.2.3-59-g8ed1b From 81796a3c6a4ad3ba0408c807ec14f50e6270ec23 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 5 Mar 2018 09:58:00 +0100 Subject: s390/decompressor: trim uncompressed image head during the build It seems to be suboptimal to compress the entire image, so that we could decompress and throw away the first 68k (0x11000) during the boot process. This patch trims 0x11000 bytes during the build process and adjusts symbols in size.h accordingly. Besides making bzImage smaller, this change would also be a benefit for kaslr. It allows to decompress the kernel right to desired offset, without worrying about dead weight in front of the decompressed image. Signed-off-by: Vasily Gorbik Acked-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/boot/compressed/Makefile | 16 ++++++++++++---- arch/s390/boot/compressed/head.S | 6 ++---- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index 26d6a94f40f6..5766f7b9b271 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -29,11 +29,16 @@ LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T $(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(call if_changed,ld) -sed-sizes := -e 's/^\([0-9a-fA-F]*\) . \(__bss_start\|_end\)$$/\#define SZ\2 0x\1/p' +TRIM_HEAD_SIZE := 0x11000 -quiet_cmd_sizes = GEN $@ +sed-sizes := -e 's/^\([0-9a-fA-F]*\) . \(__bss_start\|_end\)$$/\#define SZ\2 (0x\1 - $(TRIM_HEAD_SIZE))/p' + +quiet_cmd_sizes = GEN $@ cmd_sizes = $(NM) $< | sed -n $(sed-sizes) > $@ +quiet_cmd_trim_head = TRIM $@ + cmd_trim_head = tail -c +$$(($(TRIM_HEAD_SIZE) + 1)) $< > $@ + $(obj)/sizes.h: vmlinux $(call if_changed,sizes) @@ -43,10 +48,13 @@ $(obj)/head.o: $(obj)/sizes.h CFLAGS_misc.o += -I$(objtree)/$(obj) $(obj)/misc.o: $(obj)/sizes.h -OBJCOPYFLAGS_vmlinux.bin := -R .comment -S -$(obj)/vmlinux.bin: vmlinux +OBJCOPYFLAGS_vmlinux.bin.full := -R .comment -S +$(obj)/vmlinux.bin.full: vmlinux $(call if_changed,objcopy) +$(obj)/vmlinux.bin: $(obj)/vmlinux.bin.full + $(call if_changed,trim_head) + vmlinux.bin.all-y := $(obj)/vmlinux.bin suffix-$(CONFIG_KERNEL_GZIP) := gz diff --git a/arch/s390/boot/compressed/head.S b/arch/s390/boot/compressed/head.S index 231d1491d431..9f94eca0f467 100644 --- a/arch/s390/boot/compressed/head.S +++ b/arch/s390/boot/compressed/head.S @@ -23,12 +23,10 @@ ENTRY(startup_continue) aghi %r15,-160 brasl %r14,decompress_kernel # Set up registers for memory mover. We move the decompressed image to - # 0x11000, starting at offset 0x11000 in the decompressed image so - # that code living at 0x11000 in the image will end up at 0x11000 in - # memory. + # 0x11000, where startup_continue of the decompressed image is supposed + # to be. lgr %r4,%r2 lg %r2,.Loffset-.LPG1(%r13) - la %r4,0(%r2,%r4) lg %r3,.Lmvsize-.LPG1(%r13) lgr %r5,%r3 # Move the memory mover someplace safe so it doesn't overwrite itself. -- cgit v1.2.3-59-g8ed1b From ded27d8d2eae2aefe7d03d3e7c3fbdcd1fd501fc Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 29 Jun 2017 13:27:22 +0200 Subject: s390/cio: rename struct channel_path_desc Rename struct channel_path_desc to struct channel_path_desc_fmt0 to fit the scheme. Provide a macro for the function wrappers that gather this and related data from firmware. Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/ccwdev.h | 2 +- arch/s390/include/asm/chpid.h | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/cio/chp.c | 10 +++---- drivers/s390/cio/chp.h | 4 +-- drivers/s390/cio/chsc.c | 56 +++++++++++++++------------------------ drivers/s390/cio/chsc.h | 4 +-- drivers/s390/cio/device_ops.c | 4 +-- drivers/s390/net/qeth_core_main.c | 2 +- 9 files changed, 36 insertions(+), 50 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index 633f8da86137..20bce136b2e5 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -230,5 +230,5 @@ int ccw_device_siosl(struct ccw_device *); extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *); -struct channel_path_desc *ccw_device_get_chp_desc(struct ccw_device *, int); +struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *, int); #endif /* _S390_CCWDEV_H_ */ diff --git a/arch/s390/include/asm/chpid.h b/arch/s390/include/asm/chpid.h index 4773f747915c..20e0d22f29e9 100644 --- a/arch/s390/include/asm/chpid.h +++ b/arch/s390/include/asm/chpid.h @@ -9,7 +9,7 @@ #include #include -struct channel_path_desc { +struct channel_path_desc_fmt0 { u8 flags; u8 lsn; u8 desc; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 85b6a70ce334..be208e7adcb4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -994,7 +994,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) struct dasd_eckd_private *private, path_private; struct dasd_uid *uid; char print_path_uid[60], print_device_uid[60]; - struct channel_path_desc *chp_desc; + struct channel_path_desc_fmt0 *chp_desc; struct subchannel_id sch_id; private = device->private; diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index f95b452b8bbc..34315e65c1c8 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -422,7 +422,7 @@ int chp_update_desc(struct channel_path *chp) { int rc; - rc = chsc_determine_base_channel_path_desc(chp->chpid, &chp->desc); + rc = chsc_determine_fmt0_channel_path_desc(chp->chpid, &chp->desc); if (rc) return rc; @@ -506,20 +506,20 @@ out: * On success return a newly allocated copy of the channel-path description * data associated with the given channel-path ID. Return %NULL on error. */ -struct channel_path_desc *chp_get_chp_desc(struct chp_id chpid) +struct channel_path_desc_fmt0 *chp_get_chp_desc(struct chp_id chpid) { struct channel_path *chp; - struct channel_path_desc *desc; + struct channel_path_desc_fmt0 *desc; chp = chpid_to_chp(chpid); if (!chp) return NULL; - desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); + desc = kmalloc(sizeof(*desc), GFP_KERNEL); if (!desc) return NULL; mutex_lock(&chp->lock); - memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); + memcpy(desc, &chp->desc, sizeof(*desc)); mutex_unlock(&chp->lock); return desc; } diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index 7e80323cd261..6d2bfbbead66 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -44,7 +44,7 @@ struct channel_path { struct chp_id chpid; struct mutex lock; /* Serialize access to below members. */ int state; - struct channel_path_desc desc; + struct channel_path_desc_fmt0 desc; struct channel_path_desc_fmt1 desc_fmt1; /* Channel-measurement related stuff: */ int cmg; @@ -61,7 +61,7 @@ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) int chp_get_status(struct chp_id chpid); u8 chp_get_sch_opm(struct subchannel *sch); int chp_is_registered(struct chp_id chpid); -struct channel_path_desc *chp_get_chp_desc(struct chp_id chpid); +struct channel_path_desc_fmt0 *chp_get_chp_desc(struct chp_id chpid); void chp_remove_cmg_attr(struct channel_path *chp); int chp_add_cmg_attr(struct channel_path *chp); int chp_update_desc(struct channel_path *chp); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index c08fc5a8df0c..65290e5ac854 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -940,43 +940,29 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, } EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); -int chsc_determine_base_channel_path_desc(struct chp_id chpid, - struct channel_path_desc *desc) -{ - struct chsc_scpd *scpd_area; - unsigned long flags; - int ret; - - spin_lock_irqsave(&chsc_page_lock, flags); - scpd_area = chsc_page; - ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area); - if (ret) - goto out; - - memcpy(desc, scpd_area->data, sizeof(*desc)); -out: - spin_unlock_irqrestore(&chsc_page_lock, flags); - return ret; +#define chsc_det_chp_desc(FMT, c) \ +int chsc_determine_fmt##FMT##_channel_path_desc( \ + struct chp_id chpid, struct channel_path_desc_fmt##FMT *desc) \ +{ \ + struct chsc_scpd *scpd_area; \ + unsigned long flags; \ + int ret; \ + \ + spin_lock_irqsave(&chsc_page_lock, flags); \ + scpd_area = chsc_page; \ + ret = chsc_determine_channel_path_desc(chpid, 0, FMT, c, 0, \ + scpd_area); \ + if (ret) \ + goto out; \ + \ + memcpy(desc, scpd_area->data, sizeof(*desc)); \ +out: \ + spin_unlock_irqrestore(&chsc_page_lock, flags); \ + return ret; \ } -int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, - struct channel_path_desc_fmt1 *desc) -{ - struct chsc_scpd *scpd_area; - unsigned long flags; - int ret; - - spin_lock_irqsave(&chsc_page_lock, flags); - scpd_area = chsc_page; - ret = chsc_determine_channel_path_desc(chpid, 0, 1, 1, 0, scpd_area); - if (ret) - goto out; - - memcpy(desc, scpd_area->data, sizeof(*desc)); -out: - spin_unlock_irqrestore(&chsc_page_lock, flags); - return ret; -} +chsc_det_chp_desc(0, 0) +chsc_det_chp_desc(1, 1) static void chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index dda5953534b7..bdf2cc90e5ef 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -147,8 +147,8 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable); int chsc_chp_vary(struct chp_id chpid, int on); int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, int c, int m, void *page); -int chsc_determine_base_channel_path_desc(struct chp_id chpid, - struct channel_path_desc *desc); +int chsc_determine_fmt0_channel_path_desc(struct chp_id chpid, + struct channel_path_desc_fmt0 *desc); int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, struct channel_path_desc_fmt1 *desc); void chsc_chp_online(struct chp_id chpid); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 75ce12a24dc2..aecfebb74157 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -460,8 +460,8 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev) * On success return a newly allocated copy of the channel-path description * data associated with the given channel path. Return %NULL on error. */ -struct channel_path_desc *ccw_device_get_chp_desc(struct ccw_device *cdev, - int chp_idx) +struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *cdev, + int chp_idx) { struct subchannel *sch; struct chp_id chpid; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ca72f3311004..5f10e3aee7ed 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1361,7 +1361,7 @@ static void qeth_set_multiple_write_queues(struct qeth_card *card) static void qeth_update_from_chp_desc(struct qeth_card *card) { struct ccw_device *ccwdev; - struct channel_path_desc *chp_dsc; + struct channel_path_desc_fmt0 *chp_dsc; QETH_DBF_TEXT(SETUP, 2, "chp_desc"); -- cgit v1.2.3-59-g8ed1b From fcc6dd4b7b4dfc57ba19f988cfa5ac335de885d5 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 22 Jun 2016 19:42:40 +0200 Subject: s390/chsc: query utility strings via fmt3 channel path descriptor Add support for format 3 channel path descriptors and use them to gather utility strings. Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/css_chars.h | 6 ++++-- drivers/s390/cio/chp.c | 1 + drivers/s390/cio/chp.h | 1 + drivers/s390/cio/chsc.c | 3 +++ drivers/s390/cio/chsc.h | 7 +++++++ 5 files changed, 16 insertions(+), 2 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/css_chars.h b/arch/s390/include/asm/css_chars.h index fb56fa3283a2..0563fd3e8458 100644 --- a/arch/s390/include/asm/css_chars.h +++ b/arch/s390/include/asm/css_chars.h @@ -32,8 +32,10 @@ struct css_general_char { u32 fcx : 1; /* bit 88 */ u32 : 19; u32 alt_ssi : 1; /* bit 108 */ - u32:1; - u32 narf:1; /* bit 110 */ + u32 : 1; + u32 narf : 1; /* bit 110 */ + u32 : 12; + u32 util_str : 1;/* bit 123 */ } __packed; extern struct css_general_char css_general_characteristics; diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 34315e65c1c8..41ecc08b1cf7 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -431,6 +431,7 @@ int chp_update_desc(struct channel_path *chp) * hypervisors implement the required chsc commands. */ chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); + chsc_determine_fmt3_channel_path_desc(chp->chpid, &chp->desc_fmt3); chsc_get_channel_measurement_chars(chp); return 0; diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index 6d2bfbbead66..20259f3fbf45 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -46,6 +46,7 @@ struct channel_path { int state; struct channel_path_desc_fmt0 desc; struct channel_path_desc_fmt1 desc_fmt1; + struct channel_path_desc_fmt3 desc_fmt3; /* Channel-measurement related stuff: */ int cmg; int shared; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 65290e5ac854..6652a49a49b1 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -915,6 +915,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, return -EINVAL; if ((rfmt == 2) && !css_general_characteristics.cib) return -EINVAL; + if ((rfmt == 3) && !css_general_characteristics.util_str) + return -EINVAL; memset(page, 0, PAGE_SIZE); scpd_area = page; @@ -963,6 +965,7 @@ out: \ chsc_det_chp_desc(0, 0) chsc_det_chp_desc(1, 1) +chsc_det_chp_desc(3, 0) static void chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index bdf2cc90e5ef..5c9f0dd33f4e 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -40,6 +40,11 @@ struct channel_path_desc_fmt1 { u32 zeros[2]; } __attribute__ ((packed)); +struct channel_path_desc_fmt3 { + struct channel_path_desc_fmt1 fmt1_desc; + u8 util_str[64]; +}; + struct channel_path; struct css_chsc_char { @@ -151,6 +156,8 @@ int chsc_determine_fmt0_channel_path_desc(struct chp_id chpid, struct channel_path_desc_fmt0 *desc); int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, struct channel_path_desc_fmt1 *desc); +int chsc_determine_fmt3_channel_path_desc(struct chp_id chpid, + struct channel_path_desc_fmt3 *desc); void chsc_chp_online(struct chp_id chpid); void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); -- cgit v1.2.3-59-g8ed1b From b2e2f43a01bace1a25bdbae04c9f9846882b727a Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 23 Mar 2018 17:09:39 +0100 Subject: s390: move nobp parameter functions to nospec-branch.c Keep the code for the nobp parameter handling with the code for expolines. Both are related to the spectre v2 mitigation. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/Makefile | 4 ++-- arch/s390/kernel/alternative.c | 23 ----------------------- arch/s390/kernel/nospec-branch.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 7f27e3da9709..b06a6f79c1ec 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -61,11 +61,11 @@ obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o +obj-y += nospec-branch.o extra-y += head.o head64.o vmlinux.lds -obj-$(CONFIG_EXPOLINE) += nospec-branch.o -CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE) +CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index 22476135f738..1abf4f35d059 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -15,29 +15,6 @@ static int __init disable_alternative_instructions(char *str) early_param("noaltinstr", disable_alternative_instructions); -static int __init nobp_setup_early(char *str) -{ - bool enabled; - int rc; - - rc = kstrtobool(str, &enabled); - if (rc) - return rc; - if (enabled && test_facility(82)) - __set_facility(82, S390_lowcore.alt_stfle_fac_list); - else - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); - return 0; -} -early_param("nobp", nobp_setup_early); - -static int __init nospec_setup_early(char *str) -{ - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); - return 0; -} -early_param("nospec", nospec_setup_early); - struct brcl_insn { u16 opc; s32 disp; diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 9aff72d3abda..69ce00d02d1b 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -2,6 +2,31 @@ #include #include +static int __init nobp_setup_early(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (rc) + return rc; + if (enabled && test_facility(82)) + __set_facility(82, S390_lowcore.alt_stfle_fac_list); + else + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nobp", nobp_setup_early); + +static int __init nospec_setup_early(char *str) +{ + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nospec", nospec_setup_early); + +#ifdef CONFIG_EXPOLINE + int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); @@ -98,3 +123,5 @@ void __init nospec_init_branches(void) nospec_call_revert(__nospec_call_start, __nospec_call_end); nospec_return_revert(__nospec_return_start, __nospec_return_end); } + +#endif /* CONFIG_EXPOLINE */ -- cgit v1.2.3-59-g8ed1b From 6e179d64126b909f0b288fa63cdbf07c531e9b1d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 23 Mar 2018 13:04:49 +0100 Subject: s390: add automatic detection of the spectre defense Automatically decide between nobp vs. expolines if the spectre_v2=auto kernel parameter is specified or CONFIG_EXPOLINE_AUTO=y is set. The decision made at boot time due to CONFIG_EXPOLINE_AUTO=y being set can be overruled with the nobp, nospec and spectre_v2 kernel parameters. Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 2 +- arch/s390/Makefile | 2 +- arch/s390/include/asm/nospec-branch.h | 6 ++-- arch/s390/kernel/alternative.c | 1 + arch/s390/kernel/module.c | 11 +++--- arch/s390/kernel/nospec-branch.c | 68 +++++++++++++++++++++-------------- 6 files changed, 52 insertions(+), 38 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index eaee7087886f..90cc6d488492 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -576,7 +576,7 @@ choice config EXPOLINE_OFF bool "spectre_v2=off" -config EXPOLINE_MEDIUM +config EXPOLINE_AUTO bool "spectre_v2=auto" config EXPOLINE_FULL diff --git a/arch/s390/Makefile b/arch/s390/Makefile index bd424f6a3c5b..c79936d02f7b 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -81,7 +81,7 @@ ifdef CONFIG_EXPOLINE CC_FLAGS_EXPOLINE += -mfunction-return=thunk CC_FLAGS_EXPOLINE += -mindirect-branch-table export CC_FLAGS_EXPOLINE - cflags-y += $(CC_FLAGS_EXPOLINE) + cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE endif endif diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h index 7df48e5cf36f..35bf28fe4c64 100644 --- a/arch/s390/include/asm/nospec-branch.h +++ b/arch/s390/include/asm/nospec-branch.h @@ -6,12 +6,10 @@ #include -extern int nospec_call_disable; -extern int nospec_return_disable; +extern int nospec_disable; void nospec_init_branches(void); -void nospec_call_revert(s32 *start, s32 *end); -void nospec_return_revert(s32 *start, s32 *end); +void nospec_revert(s32 *start, s32 *end); #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index 1abf4f35d059..8e1f2aee85ef 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -2,6 +2,7 @@ #include #include #include +#include #define MAX_PATCH_LEN (255 - 1) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 1fc6d1ff92d3..5a83be955c70 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -159,7 +159,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, me->core_layout.size += me->arch.got_size; me->arch.plt_offset = me->core_layout.size; if (me->arch.plt_size) { - if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable) + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) me->arch.plt_size += PLT_ENTRY_SIZE; me->core_layout.size += me->arch.plt_size; } @@ -318,8 +318,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, info->plt_offset; ip[0] = 0x0d10e310; /* basr 1,0 */ ip[1] = 0x100a0004; /* lg 1,10(1) */ - if (IS_ENABLED(CONFIG_EXPOLINE) && - !nospec_call_disable) { + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) { unsigned int *ij; ij = me->core_layout.base + me->arch.plt_offset + @@ -440,7 +439,7 @@ int module_finalize(const Elf_Ehdr *hdr, void *aseg; if (IS_ENABLED(CONFIG_EXPOLINE) && - !nospec_call_disable && me->arch.plt_size) { + !nospec_disable && me->arch.plt_size) { unsigned int *ij; ij = me->core_layout.base + me->arch.plt_offset + @@ -467,11 +466,11 @@ int module_finalize(const Elf_Ehdr *hdr, if (IS_ENABLED(CONFIG_EXPOLINE) && (!strcmp(".nospec_call_table", secname))) - nospec_call_revert(aseg, aseg + s->sh_size); + nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && (!strcmp(".nospec_return_table", secname))) - nospec_return_revert(aseg, aseg + s->sh_size); + nospec_revert(aseg, aseg + s->sh_size); } jump_label_apply_nops(me); diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 69ce00d02d1b..192e633a79d8 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -10,10 +10,17 @@ static int __init nobp_setup_early(char *str) rc = kstrtobool(str, &enabled); if (rc) return rc; - if (enabled && test_facility(82)) + if (enabled && test_facility(82)) { + /* + * The user explicitely requested nobp=1, enable it and + * disable the expoline support. + */ __set_facility(82, S390_lowcore.alt_stfle_fac_list); - else + if (IS_ENABLED(CONFIG_EXPOLINE)) + nospec_disable = 1; + } else { __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + } return 0; } early_param("nobp", nobp_setup_early); @@ -27,31 +34,46 @@ early_param("nospec", nospec_setup_early); #ifdef CONFIG_EXPOLINE -int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); +int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); static int __init nospectre_v2_setup_early(char *str) { - nospec_call_disable = 1; - nospec_return_disable = 1; + nospec_disable = 1; return 0; } early_param("nospectre_v2", nospectre_v2_setup_early); +static int __init spectre_v2_auto_early(void) +{ + if (IS_ENABLED(CC_USING_EXPOLINE)) { + /* + * The kernel has been compiled with expolines. + * Keep expolines enabled and disable nobp. + */ + nospec_disable = 0; + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + } + /* + * If the kernel has not been compiled with expolines the + * nobp setting decides what is done, this depends on the + * CONFIG_KERNEL_NP option and the nobp/nospec parameters. + */ + return 0; +} +#ifdef CONFIG_EXPOLINE_AUTO +early_initcall(spectre_v2_auto_early); +#endif + static int __init spectre_v2_setup_early(char *str) { if (str && !strncmp(str, "on", 2)) { - nospec_call_disable = 0; - nospec_return_disable = 0; - } - if (str && !strncmp(str, "off", 3)) { - nospec_call_disable = 1; - nospec_return_disable = 1; - } - if (str && !strncmp(str, "auto", 4)) { - nospec_call_disable = 0; - nospec_return_disable = 1; + nospec_disable = 0; + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); } + if (str && !strncmp(str, "off", 3)) + nospec_disable = 1; + if (str && !strncmp(str, "auto", 4)) + spectre_v2_auto_early(); return 0; } early_param("spectre_v2", spectre_v2_setup_early); @@ -104,15 +126,9 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) } } -void __init_or_module nospec_call_revert(s32 *start, s32 *end) -{ - if (nospec_call_disable) - __nospec_revert(start, end); -} - -void __init_or_module nospec_return_revert(s32 *start, s32 *end) +void __init_or_module nospec_revert(s32 *start, s32 *end) { - if (nospec_return_disable) + if (nospec_disable) __nospec_revert(start, end); } @@ -120,8 +136,8 @@ extern s32 __nospec_call_start[], __nospec_call_end[]; extern s32 __nospec_return_start[], __nospec_return_end[]; void __init nospec_init_branches(void) { - nospec_call_revert(__nospec_call_start, __nospec_call_end); - nospec_return_revert(__nospec_return_start, __nospec_return_end); + nospec_revert(__nospec_call_start, __nospec_call_end); + nospec_revert(__nospec_return_start, __nospec_return_end); } #endif /* CONFIG_EXPOLINE */ -- cgit v1.2.3-59-g8ed1b From bc035599718412cfba9249aa713f90ef13f13ee9 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 20 Mar 2018 16:33:43 +0100 Subject: s390: report spectre mitigation via syslog Add a boot message if either of the spectre defenses is active. The message is "Spectre V2 mitigation: execute trampolines." or "Spectre V2 mitigation: limited branch prediction." Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/nospec-branch.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/s390') diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 192e633a79d8..adec38c5f53b 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -32,6 +32,16 @@ static int __init nospec_setup_early(char *str) } early_param("nospec", nospec_setup_early); +static int __init nospec_report(void) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + pr_info("Spectre V2 mitigation: execute trampolines.\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + pr_info("Spectre V2 mitigation: limited branch prediction.\n"); + return 0; +} +arch_initcall(nospec_report); + #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -- cgit v1.2.3-59-g8ed1b From d424986f1d6b16079b3231db0314923f4f8deed1 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 21 Mar 2018 09:38:21 +0100 Subject: s390: add sysfs attributes for spectre Set CONFIG_GENERIC_CPU_VULNERABILITIES and provide the two functions cpu_show_spectre_v1 and cpu_show_spectre_v2 to report the spectre mitigations. Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 1 + arch/s390/kernel/nospec-branch.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'arch/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 90cc6d488492..32a0d5b958bf 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -120,6 +120,7 @@ config S390 select GENERIC_CLOCKEVENTS select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_DEVICES if !SMP + select GENERIC_CPU_VULNERABILITIES select GENERIC_FIND_FIRST_BIT select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index adec38c5f53b..14867ec5f726 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include static int __init nobp_setup_early(char *str) @@ -42,6 +43,24 @@ static int __init nospec_report(void) } arch_initcall(nospec_report); +#ifdef CONFIG_SYSFS +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + return sprintf(buf, "Mitigation: execute trampolines\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + return sprintf(buf, "Mitigation: limited branch prediction.\n"); + return sprintf(buf, "Vulnerable\n"); +} +#endif + #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -- cgit v1.2.3-59-g8ed1b From fba9eb7946251d6e420df3bdf7bc45195be7be9a Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 19 Mar 2018 18:07:31 +0100 Subject: s390: add assembler macros for CPU alternatives Add a header with macros usable in assembler files to emit alternative code sequences. It works analog to the alternatives for inline assmeblies in C files, with the same restrictions and capabilities. The syntax is ALTERNATIVE "", \ "", \ "" and ALTERNATIVE_2 "", \ "", \ "", "", \ "" Reviewed-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/alternative-asm.h | 108 ++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 arch/s390/include/asm/alternative-asm.h (limited to 'arch/s390') diff --git a/arch/s390/include/asm/alternative-asm.h b/arch/s390/include/asm/alternative-asm.h new file mode 100644 index 000000000000..955d620db23e --- /dev/null +++ b/arch/s390/include/asm/alternative-asm.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_ALTERNATIVE_ASM_H +#define _ASM_S390_ALTERNATIVE_ASM_H + +#ifdef __ASSEMBLY__ + +/* + * Check the length of an instruction sequence. The length may not be larger + * than 254 bytes and it has to be divisible by 2. + */ +.macro alt_len_check start,end + .if ( \end - \start ) > 254 + .error "cpu alternatives does not support instructions blocks > 254 bytes\n" + .endif + .if ( \end - \start ) % 2 + .error "cpu alternatives instructions length is odd\n" + .endif +.endm + +/* + * Issue one struct alt_instr descriptor entry (need to put it into + * the section .altinstructions, see below). This entry contains + * enough information for the alternatives patching code to patch an + * instruction. See apply_alternatives(). + */ +.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature + .long \orig_start - . + .long \alt_start - . + .word \feature + .byte \orig_end - \orig_start + .byte \alt_end - \alt_start +.endm + +/* + * Fill up @bytes with nops. The macro emits 6-byte nop instructions + * for the bulk of the area, possibly followed by a 4-byte and/or + * a 2-byte nop if the size of the area is not divisible by 6. + */ +.macro alt_pad_fill bytes + .fill ( \bytes ) / 6, 6, 0xc0040000 + .fill ( \bytes ) % 6 / 4, 4, 0x47000000 + .fill ( \bytes ) % 6 % 4 / 2, 2, 0x0700 +.endm + +/* + * Fill up @bytes with nops. If the number of bytes is larger + * than 6, emit a jg instruction to branch over all nops, then + * fill an area of size (@bytes - 6) with nop instructions. + */ +.macro alt_pad bytes + .if ( \bytes > 0 ) + .if ( \bytes > 6 ) + jg . + \bytes + alt_pad_fill \bytes - 6 + .else + alt_pad_fill \bytes + .endif + .endif +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE oldinstr, newinstr, feature + .pushsection .altinstr_replacement,"ax" +770: \newinstr +771: .popsection +772: \oldinstr +773: alt_len_check 770b, 771b + alt_len_check 772b, 773b + alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) ) +774: .pushsection .altinstructions,"a" + alt_entry 772b, 774b, 770b, 771b, \feature + .popsection +.endm + +/* + * Define an alternative between two instructions. If @feature is + * present, early code in apply_alternatives() replaces @oldinstr with + * @newinstr. ".skip" directive takes care of proper instruction padding + * in case @newinstr is longer than @oldinstr. + */ +.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 + .pushsection .altinstr_replacement,"ax" +770: \newinstr1 +771: \newinstr2 +772: .popsection +773: \oldinstr +774: alt_len_check 770b, 771b + alt_len_check 771b, 772b + alt_len_check 773b, 774b + .if ( 771b - 770b > 772b - 771b ) + alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) ) + .else + alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) ) + .endif +775: .pushsection .altinstructions,"a" + alt_entry 773b, 775b, 770b, 771b,\feature1 + alt_entry 773b, 775b, 771b, 772b,\feature2 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_ALTERNATIVE_ASM_H */ -- cgit v1.2.3-59-g8ed1b From b058661a993aafc718ce713221bb1d57588c3710 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 26 Mar 2018 15:27:36 +0200 Subject: s390/entry.S: use assembler alternatives Replace the open coded alternatives for the BPOFF, BPON, BPENTER, and BPEXIT macros with the new magic from asm/alternatives-asm.h to make the code easier to read. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/entry.S | 56 ++++++------------------------------------------ 1 file changed, 7 insertions(+), 49 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 73492461c454..ee1b2f7b3d05 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -162,65 +163,22 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) .endm .macro BPOFF - .pushsection .altinstr_replacement, "ax" -660: .long 0xb2e8c000 - .popsection -661: .long 0x47000000 - .pushsection .altinstructions, "a" - .long 661b - . - .long 660b - . - .word 82 - .byte 4 - .byte 4 - .popsection + ALTERNATIVE "", ".long 0xb2e8c000", 82 .endm .macro BPON - .pushsection .altinstr_replacement, "ax" -662: .long 0xb2e8d000 - .popsection -663: .long 0x47000000 - .pushsection .altinstructions, "a" - .long 663b - . - .long 662b - . - .word 82 - .byte 4 - .byte 4 - .popsection + ALTERNATIVE "", ".long 0xb2e8d000", 82 .endm .macro BPENTER tif_ptr,tif_mask - .pushsection .altinstr_replacement, "ax" -662: .word 0xc004, 0x0000, 0x0000 # 6 byte nop - .word 0xc004, 0x0000, 0x0000 # 6 byte nop - .popsection -664: TSTMSK \tif_ptr,\tif_mask - jz . + 8 - .long 0xb2e8d000 - .pushsection .altinstructions, "a" - .long 664b - . - .long 662b - . - .word 82 - .byte 12 - .byte 12 - .popsection + ALTERNATIVE "TSTMSK \tif_ptr,\tif_mask; jz .+8; .long 0xb2e8d000", \ + "", 82 .endm .macro BPEXIT tif_ptr,tif_mask TSTMSK \tif_ptr,\tif_mask - .pushsection .altinstr_replacement, "ax" -662: jnz . + 8 - .long 0xb2e8d000 - .popsection -664: jz . + 8 - .long 0xb2e8c000 - .pushsection .altinstructions, "a" - .long 664b - . - .long 662b - . - .word 82 - .byte 8 - .byte 8 - .popsection + ALTERNATIVE "jz .+8; .long 0xb2e8c000", \ + "jnz .+8; .long 0xb2e8d000", 82 .endm #ifdef CONFIG_EXPOLINE -- cgit v1.2.3-59-g8ed1b From e5b98199deb013609af7106a1fb9e779a7f6744a Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 26 Mar 2018 15:23:33 +0200 Subject: s390/lpp: use assembler alternatives for the LPP instruction With the new macros for CPU alternatives the MACHINE_FLAG_LPP check around the LPP instruction can be optimized. After this is done the flag can be removed. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/cpu_mf.h | 4 ++-- arch/s390/include/asm/setup.h | 2 -- arch/s390/kernel/early.c | 2 -- arch/s390/kernel/entry.S | 14 ++++++-------- 4 files changed, 8 insertions(+), 14 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index dd08db491b89..f58d17e9dd65 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -29,12 +29,12 @@ /* CPU measurement facility support */ static inline int cpum_cf_avail(void) { - return MACHINE_HAS_LPP && test_facility(67); + return test_facility(40) && test_facility(67); } static inline int cpum_sf_avail(void) { - return MACHINE_HAS_LPP && test_facility(68); + return test_facility(40) && test_facility(68); } diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 2eb0c8a7b664..124154fdfc97 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -25,7 +25,6 @@ #define MACHINE_FLAG_DIAG44 _BITUL(6) #define MACHINE_FLAG_EDAT1 _BITUL(7) #define MACHINE_FLAG_EDAT2 _BITUL(8) -#define MACHINE_FLAG_LPP _BITUL(9) #define MACHINE_FLAG_TOPOLOGY _BITUL(10) #define MACHINE_FLAG_TE _BITUL(11) #define MACHINE_FLAG_TLB_LC _BITUL(12) @@ -66,7 +65,6 @@ extern void detect_memory_memblock(void); #define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44) #define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1) #define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2) -#define MACHINE_HAS_LPP (S390_lowcore.machine_flags & MACHINE_FLAG_LPP) #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 53d089fc4501..b00b515baa53 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -242,8 +242,6 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2; if (test_facility(3)) S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; - if (test_facility(40)) - S390_lowcore.machine_flags |= MACHINE_FLAG_LPP; if (test_facility(50) && test_facility(73)) { S390_lowcore.machine_flags |= MACHINE_FLAG_TE; __ctl_set_bit(0, 55); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index ee1b2f7b3d05..0aa205e32f7d 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -58,6 +58,8 @@ _CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \ _CIF_ASCE_SECONDARY | _CIF_FPU) _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) +_LPP_OFFSET = __LC_LPP + #define BASED(name) name-cleanup_critical(%r13) .macro TRACE_IRQS_ON @@ -281,10 +283,8 @@ ENTRY(__switch_to) aghi %r3,__TASK_pid mvc __LC_CURRENT_PID(4,%r0),0(%r3) # store pid of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task - TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP - jz 0f - .insn s,0xb2800000,__LC_LPP # set program parameter -0: BR_R1USE_R14 + ALTERNATIVE "", ".insn s,0xb2800000,_LPP_OFFSET", 40 + BR_R1USE_R14 .L__critical_start: @@ -1243,10 +1243,8 @@ ENTRY(mcck_int_handler) # PSW restart interrupt handler # ENTRY(restart_int_handler) - TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP - jz 0f - .insn s,0xb2800000,__LC_LPP -0: stg %r15,__LC_SAVE_AREA_RESTART + ALTERNATIVE "", ".insn s,0xb2800000,_LPP_OFFSET", 40 + stg %r15,__LC_SAVE_AREA_RESTART lg %r15,__LC_RESTART_STACK aghi %r15,-__PT_SIZE # create pt_regs on stack xc 0(__PT_SIZE,%r15),0(%r15) -- cgit v1.2.3-59-g8ed1b From 92fa7a13c845c91f6a8177250474bbcab7fcf45e Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 20 Mar 2018 13:33:43 +0100 Subject: s390/kvm: improve stack frame constants in entry.S The code in sie64a uses the stack frame passed to the function to store some temporary data in the empty1 array (see struct stack_frame in asm/processor.h. Replace the __SF_EMPTY+x constants with a properly defined offset: s/__SF_EMPTY/__SF_SIE_CONTROL/, s/__SF_EMPTY+8/__SF_SIE_SAVEAREA/, s/__SF_EMPTY+16/__SF_SIE_REASON/, s/__SF_EMPTY+24/__SF_SIE_FLAGS/. Reviewed-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/asm-offsets.c | 1 + arch/s390/kernel/entry.S | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'arch/s390') diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 587b195b588d..cfe2c45c5180 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -63,6 +63,7 @@ int main(void) OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[0]); OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[1]); OFFSET(__SF_SIE_REASON, stack_frame, empty1[2]); + OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[3]); BLANK(); /* timeval/timezone offsets for use by vdso */ OFFSET(__VDSO_UPD_COUNT, vdso_data, tb_update_count); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 0aa205e32f7d..b52b6acd4548 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -297,10 +297,10 @@ ENTRY(__switch_to) ENTRY(sie64a) stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers lg %r12,__LC_CURRENT - stg %r2,__SF_EMPTY(%r15) # save control block pointer - stg %r3,__SF_EMPTY+8(%r15) # save guest register save area - xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0 - mvc __SF_EMPTY+24(8,%r15),__TI_flags(%r12) # copy thread flags + stg %r2,__SF_SIE_CONTROL(%r15) # save control block pointer + stg %r3,__SF_SIE_SAVEAREA(%r15) # save guest register save area + xc __SF_SIE_REASON(8,%r15),__SF_SIE_REASON(%r15) # reason code = 0 + mvc __SF_SIE_FLAGS(8,%r15),__TI_flags(%r12) # copy thread flags TSTMSK __LC_CPU_FLAGS,_CIF_FPU # load guest fp/vx registers ? jno .Lsie_load_guest_gprs brasl %r14,load_fpu_regs # load guest fp/vx regs @@ -311,18 +311,18 @@ ENTRY(sie64a) jz .Lsie_gmap lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce .Lsie_gmap: - lg %r14,__SF_EMPTY(%r15) # get control block pointer + lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now tm __SIE_PROG20+3(%r14),3 # last exit... jnz .Lsie_skip TSTMSK __LC_CPU_FLAGS,_CIF_FPU jo .Lsie_skip # exit if fp/vx regs changed - BPEXIT __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + BPEXIT __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_entry: sie 0(%r14) .Lsie_exit: BPOFF - BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_skip: ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce @@ -341,7 +341,7 @@ ENTRY(sie64a) nopr 7 .globl sie_exit sie_exit: - lg %r14,__SF_EMPTY+8(%r15) # load guest register save area + lg %r14,__SF_SIE_SAVEAREA(%r15) # load guest register save area stmg %r0,%r13,0(%r14) # save guest gprs 0-13 xgr %r0,%r0 # clear guest registers to xgr %r1,%r1 # prevent speculative use @@ -350,11 +350,11 @@ sie_exit: xgr %r4,%r4 xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers - lg %r2,__SF_EMPTY+16(%r15) # return exit reason code + lg %r2,__SF_SIE_REASON(%r15) # return exit reason code BR_R1USE_R14 .Lsie_fault: lghi %r14,-EFAULT - stg %r14,__SF_EMPTY+16(%r15) # set exit reason code + stg %r14,__SF_SIE_REASON(%r15) # set exit reason code j sie_exit EX_TABLE(.Lrewind_pad6,.Lsie_fault) @@ -643,7 +643,7 @@ ENTRY(pgm_check_handler) slg %r14,BASED(.Lsie_critical_start) clg %r14,BASED(.Lsie_critical_length) jhe 0f - lg %r14,__SF_EMPTY(%r15) # get control block pointer + lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit @@ -1353,8 +1353,8 @@ cleanup_critical: clg %r9,BASED(.Lsie_crit_mcck_length) jh 1f oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST -1: BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) - lg %r9,__SF_EMPTY(%r15) # get control block pointer +1: BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + lg %r9,__SF_SIE_CONTROL(%r15) # get control block pointer ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit -- cgit v1.2.3-59-g8ed1b