xref: /kvm-unit-tests/lib/s390x/malloc_io.c (revision 8fdb51a145fda2cfce07112dc43faae66bdf6cda)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * I/O page allocation
4  *
5  * Copyright (c) 2021 IBM Corp
6  *
7  * Authors:
8  *  Pierre Morel <pmorel@linux.ibm.com>
9  *
10  * Using this interface provide host access to the allocated pages in
11  * case the guest is a protected guest.
12  * This is needed for I/O buffers.
13  *
14  */
15 #include <libcflat.h>
16 #include <asm/page.h>
17 #include <asm/uv.h>
18 #include <malloc_io.h>
19 #include <alloc_page.h>
20 #include <asm/facility.h>
21 #include <bitops.h>
22 #include <uv.h>
23 
share_pages(void * p,int count)24 static int share_pages(void *p, int count)
25 {
26 	int i = 0;
27 
28 	for (i = 0; i < count; i++, p += PAGE_SIZE)
29 		if (uv_set_shared((unsigned long)p))
30 			break;
31 	return i;
32 }
33 
unshare_pages(void * p,int count)34 static void unshare_pages(void *p, int count)
35 {
36 	int i;
37 
38 	for (i = count; i > 0; i--, p += PAGE_SIZE)
39 		uv_remove_shared((unsigned long)p);
40 }
41 
alloc_io_mem(int size,int flags)42 void *alloc_io_mem(int size, int flags)
43 {
44 	int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT);
45 	void *p;
46 	int n;
47 
48 	assert(size);
49 
50 	p = alloc_pages_flags(order, AREA_DMA31 | flags);
51 	if (!p || !uv_os_is_guest())
52 		return p;
53 
54 	n = share_pages(p, 1 << order);
55 	if (n == 1 << order)
56 		return p;
57 
58 	unshare_pages(p, n);
59 	free_pages(p);
60 	return NULL;
61 }
62 
free_io_mem(void * p,int size)63 void free_io_mem(void *p, int size)
64 {
65 	int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT);
66 
67 	assert(IS_ALIGNED((uintptr_t)p, PAGE_SIZE));
68 
69 	if (uv_os_is_guest())
70 		unshare_pages(p, 1 << order);
71 	free_pages(p);
72 }
73