Message ID | 20200207113958.7320-5-borntraeger@de.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: s390: Add support for protected VMs | expand |
[...] > #if defined(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) || \ > diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c > index f2ab2528859f..5f178d557cc8 100644 > --- a/arch/s390/kernel/setup.c > +++ b/arch/s390/kernel/setup.c > @@ -560,6 +560,8 @@ static void __init setup_memory_end(void) > vmax = _REGION1_SIZE; /* 4-level kernel page table */ > } > > + adjust_to_uv_max(&vmax); I'd somewhat prefer if (prot_virt_host) adjust_to_uv_max(&vmax); > + > /* module area is at the end of the kernel address space. */ > MODULES_END = vmax; > MODULES_VADDR = MODULES_END - MODULES_LEN; > @@ -1140,6 +1142,7 @@ void __init setup_arch(char **cmdline_p) > */ > memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT)); > > + setup_uv(); and if (prot_virt_host) setup_uv(); Moving the checks out of the functions. Makes it clearer that this is optional. > setup_memory_end(); > setup_memory(); > dma_contiguous_reserve(memory_end); > diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c > index fbf2a98de642..a06a628a88da 100644 > --- a/arch/s390/kernel/uv.c > +++ b/arch/s390/kernel/uv.c > @@ -46,4 +46,57 @@ static int __init prot_virt_setup(char *val) > return rc; > } > early_param("prot_virt", prot_virt_setup); > + > +static int __init uv_init(unsigned long stor_base, unsigned long stor_len) > +{ > + struct uv_cb_init uvcb = { > + .header.cmd = UVC_CMD_INIT_UV, > + .header.len = sizeof(uvcb), > + .stor_origin = stor_base, > + .stor_len = stor_len, > + }; > + int cc; > + > + cc = uv_call(0, (uint64_t)&uvcb); Could do int cc = uv_call(0, (uint64_t)&uvcb); > + if (cc || uvcb.header.rc != UVC_RC_EXECUTED) { > + pr_err("Ultravisor init failed with cc: %d rc: 0x%hx\n", cc, > + uvcb.header.rc); > + return -1; > + } > + return 0; > +} > + > +void __init setup_uv(void) > +{ > + unsigned long uv_stor_base; > + > + if (!prot_virt_host) > + return; > + > + uv_stor_base = (unsigned long)memblock_alloc_try_nid( > + uv_info.uv_base_stor_len, SZ_1M, SZ_2G, > + MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); > + if (!uv_stor_base) { > + pr_info("Failed to reserve %lu bytes for ultravisor base storage\n", > + uv_info.uv_base_stor_len); pr_err() ? pr_warn()? > + goto fail; > + } > + > + if (uv_init(uv_stor_base, uv_info.uv_base_stor_len)) { > + memblock_free(uv_stor_base, uv_info.uv_base_stor_len); > + goto fail; > + } > + > + pr_info("Reserving %luMB as ultravisor base storage\n", > + uv_info.uv_base_stor_len >> 20); > + return; > +fail: I'd add here: pr_info("Disabling support for protected virtualization"); > + prot_virt_host = 0;> +} > + > +void adjust_to_uv_max(unsigned long *vmax) > +{ > + if (prot_virt_host && *vmax > uv_info.max_sec_stor_addr) > + *vmax = uv_info.max_sec_stor_addr; Once you move the prot virt check out of this function *vmax = max_t(unsigned long, *vmax, uv_info.max_sec_stor_addr); > +} > #endif >
On 14.02.20 11:25, David Hildenbrand wrote: > [...] > >> #if defined(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) || \ >> diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c >> index f2ab2528859f..5f178d557cc8 100644 >> --- a/arch/s390/kernel/setup.c >> +++ b/arch/s390/kernel/setup.c >> @@ -560,6 +560,8 @@ static void __init setup_memory_end(void) >> vmax = _REGION1_SIZE; /* 4-level kernel page table */ >> } >> >> + adjust_to_uv_max(&vmax); > > I'd somewhat prefer > > if (prot_virt_host) > adjust_to_uv_max(&vmax); > >> + fine with me. ack >> /* module area is at the end of the kernel address space. */ >> MODULES_END = vmax; >> MODULES_VADDR = MODULES_END - MODULES_LEN; >> @@ -1140,6 +1142,7 @@ void __init setup_arch(char **cmdline_p) >> */ >> memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT)); >> >> + setup_uv(); > > and > > if (prot_virt_host) > setup_uv(); ack > > Moving the checks out of the functions. Makes it clearer that this is > optional. > >> setup_memory_end(); >> setup_memory(); >> dma_contiguous_reserve(memory_end); >> diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c >> index fbf2a98de642..a06a628a88da 100644 >> --- a/arch/s390/kernel/uv.c >> +++ b/arch/s390/kernel/uv.c >> @@ -46,4 +46,57 @@ static int __init prot_virt_setup(char *val) >> return rc; >> } >> early_param("prot_virt", prot_virt_setup); >> + >> +static int __init uv_init(unsigned long stor_base, unsigned long stor_len) >> +{ >> + struct uv_cb_init uvcb = { >> + .header.cmd = UVC_CMD_INIT_UV, >> + .header.len = sizeof(uvcb), >> + .stor_origin = stor_base, >> + .stor_len = stor_len, >> + }; >> + int cc; >> + >> + cc = uv_call(0, (uint64_t)&uvcb); > > Could do > > int cc = uv_call(0, (uint64_t)&uvcb); I could actually get rid of the cc and the comparison with UVC_RC_EXECUTED. When the condition code is 0, rc must be 1. Something like if (uv_call(0,..... > >> + if (cc || uvcb.header.rc != UVC_RC_EXECUTED) { >> + pr_err("Ultravisor init failed with cc: %d rc: 0x%hx\n", cc, >> + uvcb.header.rc); >> + return -1; >> + } >> + return 0; >> +} >> + >> +void __init setup_uv(void) >> +{ >> + unsigned long uv_stor_base; >> + >> + if (!prot_virt_host) >> + return; >> + >> + uv_stor_base = (unsigned long)memblock_alloc_try_nid( >> + uv_info.uv_base_stor_len, SZ_1M, SZ_2G, >> + MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); >> + if (!uv_stor_base) { >> + pr_info("Failed to reserve %lu bytes for ultravisor base storage\n", >> + uv_info.uv_base_stor_len); > > pr_err() ? pr_warn() ack. > >> + goto fail; >> + } >> + >> + if (uv_init(uv_stor_base, uv_info.uv_base_stor_len)) { >> + memblock_free(uv_stor_base, uv_info.uv_base_stor_len); >> + goto fail; >> + } >> + >> + pr_info("Reserving %luMB as ultravisor base storage\n", >> + uv_info.uv_base_stor_len >> 20); >> + return; >> +fail: > > I'd add here: > > pr_info("Disabling support for protected virtualization"); ack > >> + prot_virt_host = 0;> +} >> + >> +void adjust_to_uv_max(unsigned long *vmax) >> +{ >> + if (prot_virt_host && *vmax > uv_info.max_sec_stor_addr) >> + *vmax = uv_info.max_sec_stor_addr; > > Once you move the prot virt check out of this function > > *vmax = max_t(unsigned long, *vmax, uv_info.max_sec_stor_addr); ack > >> +} >> #endif >> > >
>> >>> + prot_virt_host = 0;> +} >>> + >>> +void adjust_to_uv_max(unsigned long *vmax) >>> +{ >>> + if (prot_virt_host && *vmax > uv_info.max_sec_stor_addr) >>> + *vmax = uv_info.max_sec_stor_addr; >> >> Once you move the prot virt check out of this function > > >> >> *vmax = max_t(unsigned long, *vmax, uv_info.max_sec_stor_addr); actually min_t, sorry :)
diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index cc7b0b0bc874..9e988543201f 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -23,12 +23,14 @@ #define UVC_RC_NO_RESUME 0x0007 #define UVC_CMD_QUI 0x0001 +#define UVC_CMD_INIT_UV 0x000f #define UVC_CMD_SET_SHARED_ACCESS 0x1000 #define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001 /* Bits in installed uv calls */ enum uv_cmds_inst { BIT_UVC_CMD_QUI = 0, + BIT_UVC_CMD_INIT_UV = 1, BIT_UVC_CMD_SET_SHARED_ACCESS = 8, BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9, }; @@ -59,6 +61,14 @@ struct uv_cb_qui { u64 reserveda0; } __packed __aligned(8); +struct uv_cb_init { + struct uv_cb_header header; + u64 reserved08[2]; + u64 stor_origin; + u64 stor_len; + u64 reserved28[4]; +} __packed __aligned(8); + struct uv_cb_share { struct uv_cb_header header; u64 reserved08[3]; @@ -158,8 +168,13 @@ static inline int is_prot_virt_host(void) { return prot_virt_host; } + +void setup_uv(void); +void adjust_to_uv_max(unsigned long *vmax); #else #define is_prot_virt_host() 0 +static inline void setup_uv(void) {} +static inline void adjust_to_uv_max(unsigned long *vmax) {} #endif #if defined(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) || \ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f2ab2528859f..5f178d557cc8 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -560,6 +560,8 @@ static void __init setup_memory_end(void) vmax = _REGION1_SIZE; /* 4-level kernel page table */ } + adjust_to_uv_max(&vmax); + /* module area is at the end of the kernel address space. */ MODULES_END = vmax; MODULES_VADDR = MODULES_END - MODULES_LEN; @@ -1140,6 +1142,7 @@ void __init setup_arch(char **cmdline_p) */ memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT)); + setup_uv(); setup_memory_end(); setup_memory(); dma_contiguous_reserve(memory_end); diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index fbf2a98de642..a06a628a88da 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -46,4 +46,57 @@ static int __init prot_virt_setup(char *val) return rc; } early_param("prot_virt", prot_virt_setup); + +static int __init uv_init(unsigned long stor_base, unsigned long stor_len) +{ + struct uv_cb_init uvcb = { + .header.cmd = UVC_CMD_INIT_UV, + .header.len = sizeof(uvcb), + .stor_origin = stor_base, + .stor_len = stor_len, + }; + int cc; + + cc = uv_call(0, (uint64_t)&uvcb); + if (cc || uvcb.header.rc != UVC_RC_EXECUTED) { + pr_err("Ultravisor init failed with cc: %d rc: 0x%hx\n", cc, + uvcb.header.rc); + return -1; + } + return 0; +} + +void __init setup_uv(void) +{ + unsigned long uv_stor_base; + + if (!prot_virt_host) + return; + + uv_stor_base = (unsigned long)memblock_alloc_try_nid( + uv_info.uv_base_stor_len, SZ_1M, SZ_2G, + MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE); + if (!uv_stor_base) { + pr_info("Failed to reserve %lu bytes for ultravisor base storage\n", + uv_info.uv_base_stor_len); + goto fail; + } + + if (uv_init(uv_stor_base, uv_info.uv_base_stor_len)) { + memblock_free(uv_stor_base, uv_info.uv_base_stor_len); + goto fail; + } + + pr_info("Reserving %luMB as ultravisor base storage\n", + uv_info.uv_base_stor_len >> 20); + return; +fail: + prot_virt_host = 0; +} + +void adjust_to_uv_max(unsigned long *vmax) +{ + if (prot_virt_host && *vmax > uv_info.max_sec_stor_addr) + *vmax = uv_info.max_sec_stor_addr; +} #endif