aboutsummaryrefslogtreecommitdiff
path: root/drivers/base/ump/example_user_api.c
blob: e3d55f652949182a55a473cc89b037ee4d480e45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 *
 * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */



#include <ump/ump.h>
#include <memory.h>
#include <stdio.h>

/*
 * Example routine to exercise the user space UMP api.
 * This routine initializes the UMP api and allocates some CPU+device X memory.
 * No usage hints are given, so the driver will use the default cacheability policy.
 * With the allocation it creates a duplicate handle and plays with the reference count.
 * Then it simulates interacting with a device and contains pseudo code for the device.
 *
 * If any error is detected correct cleanup will be performed and -1 will be returned.
 * If successful then 0 will be returned.
 */

static int test_ump_user_api(void)
{
	/* This is the size we try to allocate*/
	const size_t alloc_size = 4096;

	ump_handle h = UMP_INVALID_MEMORY_HANDLE;
	ump_handle h_copy = UMP_INVALID_MEMORY_HANDLE;
	ump_handle h_clone = UMP_INVALID_MEMORY_HANDLE;

	void * mapping = NULL;

	ump_result ump_api_res;
	int result = -1;

	ump_secure_id id;

	size_t size_returned;

	ump_api_res = ump_open();
	if (UMP_OK != ump_api_res)
	{
		/* failed to open an ump session */
		/* early out */
		return -1;
	}

	h = ump_allocate_64(alloc_size, UMP_PROT_CPU_RD | UMP_PROT_CPU_WR | UMP_PROT_X_RD | UMP_PROT_X_WR);
	/* the refcount is now 1 */
	if (UMP_INVALID_MEMORY_HANDLE == h)
	{
		/* allocation failure */
		goto cleanup;
	}

	/* this is how we could share this allocation with another process */

	/* in process A: */
	id = ump_secure_id_get(h);
	/* still ref count 1 */
	/* send the id to process B */

	/* in process B: */
	/* receive the id from A */
	h_clone = ump_from_secure_id(id);
	/* the ref count of the allocation is now 2 (one from each handle to it) */
	/* do something ... */
	/* release our clone */
	ump_release(h_clone); /* safe to call even if ump_from_secure_id failed */
	h_clone = UMP_INVALID_MEMORY_HANDLE;


	/* a simple save-for-future-use logic inside the driver would just copy the handle (but add a ref manually too!) */
	/*
	 * void assign_memory_to_job(h)
	 * {
	  */
	h_copy = h;
	ump_retain(h_copy); /* manual retain needed as we just assigned the handle, now 2 */
	/*
	 * }
	 *
	 * void job_completed(void)
	 * {
	 */
	 ump_release(h_copy); /* normal handle release as if we got via an ump_allocate */
	 h_copy = UMP_INVALID_MEMORY_HANDLE;
	 /*
	 * }
	 */
	
	/* we're now back at ref count 1, and only h is a valid handle */
	/* enough handle duplication show-off, let's play with the contents instead */

	mapping = ump_map(h, 0, alloc_size);
	if (NULL == mapping)
	{
		/* mapping failure, either out of address space or some other error */
		goto cleanup;
	}

	memset(mapping, 0, alloc_size);

	/* let's pretend we're going to start some hw device on this buffer and read the result afterwards */
	ump_cpu_msync_now(h, UMP_MSYNC_CLEAN, mapping, alloc_size);
 	/*
		device cache invalidate

		memory barrier

		start device

		memory barrier

		wait for device

		memory barrier

		device cache clean

		memory barrier
	*/
	ump_cpu_msync_now(h, UMP_MSYNC_CLEAN_AND_INVALIDATE, mapping, alloc_size);

	/* we could now peek at the result produced by the hw device, which is now accessible via our mapping */

	/* unmap the buffer when we're done with it */
	ump_unmap(h, mapping, alloc_size);

	result = 0;

cleanup:
	ump_release(h);
	h = UMP_INVALID_MEMORY_HANDLE;

	ump_close();

	return result;
}