Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] replace diag10() with diag10_range() function

Currently the diag10() function can only release one page. For exploiters
that have to call diag10 on a contiguous memory region this is suboptimal.
This patch replaces the diag10() function with diag10_range() that is
able to release multiple pages. In addition to that the new function now
allows to release memory with addresses higher than 2047 MiB. This was
due to a restriction of the diagnose implementation under z/VM prior to
release 5.2.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Michael Holzheu and committed by
Martin Schwidefsky
83ace270 91d37808

+16 -24
+15 -2
arch/s390/include/asm/diag.h
··· 9 9 #define _ASM_S390_DIAG_H 10 10 11 11 /* 12 - * Diagnose 10: Release pages 12 + * Diagnose 10: Release page range 13 13 */ 14 - extern void diag10(unsigned long addr); 14 + static inline void diag10_range(unsigned long start_pfn, unsigned long num_pfn) 15 + { 16 + unsigned long start_addr, end_addr; 17 + 18 + start_addr = start_pfn << PAGE_SHIFT; 19 + end_addr = (start_pfn + num_pfn - 1) << PAGE_SHIFT; 20 + 21 + asm volatile( 22 + "0: diag %0,%1,0x10\n" 23 + "1:\n" 24 + EX_TABLE(0b, 1b) 25 + EX_TABLE(1b, 1b) 26 + : : "a" (start_addr), "a" (end_addr)); 27 + } 15 28 16 29 /* 17 30 * Diagnose 14: Input spool file manipulation
-21
arch/s390/kernel/diag.c
··· 9 9 #include <asm/diag.h> 10 10 11 11 /* 12 - * Diagnose 10: Release pages 13 - */ 14 - void diag10(unsigned long addr) 15 - { 16 - if (addr >= 0x7ff00000) 17 - return; 18 - asm volatile( 19 - #ifdef CONFIG_64BIT 20 - " sam31\n" 21 - " diag %0,%0,0x10\n" 22 - "0: sam64\n" 23 - #else 24 - " diag %0,%0,0x10\n" 25 - "0:\n" 26 - #endif 27 - EX_TABLE(0b, 0b) 28 - : : "a" (addr)); 29 - } 30 - EXPORT_SYMBOL(diag10); 31 - 32 - /* 33 12 * Diagnose 14: Input spool file manipulation 34 13 */ 35 14 int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode)
+1 -1
arch/s390/mm/cmm.c
··· 91 91 } else 92 92 free_page((unsigned long) npa); 93 93 } 94 - diag10(addr); 94 + diag10_range(addr >> PAGE_SHIFT, 1); 95 95 pa->pages[pa->index++] = addr; 96 96 (*counter)++; 97 97 spin_unlock(&cmm_lock);