|
5 | 5 | #include <linux/anon_inodes.h> |
6 | 6 | #include <linux/device.h> |
7 | 7 | #include <linux/idr.h> |
| 8 | +#include <linux/io.h> |
8 | 9 | #include <linux/mm.h> |
9 | 10 | #include <linux/sched.h> |
10 | 11 | #include <linux/slab.h> |
@@ -202,6 +203,70 @@ struct tee_shm *tee_shm_alloc_priv_buf(struct tee_context *ctx, size_t size) |
202 | 203 | } |
203 | 204 | EXPORT_SYMBOL_GPL(tee_shm_alloc_priv_buf); |
204 | 205 |
|
| 206 | +int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align, |
| 207 | + int (*shm_register)(struct tee_context *ctx, |
| 208 | + struct tee_shm *shm, |
| 209 | + struct page **pages, |
| 210 | + size_t num_pages, |
| 211 | + unsigned long start)) |
| 212 | +{ |
| 213 | + size_t nr_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE; |
| 214 | + struct page **pages; |
| 215 | + unsigned int i; |
| 216 | + int rc = 0; |
| 217 | + |
| 218 | + /* |
| 219 | + * Ignore alignment since this is already going to be page aligned |
| 220 | + * and there's no need for any larger alignment. |
| 221 | + */ |
| 222 | + shm->kaddr = alloc_pages_exact(nr_pages * PAGE_SIZE, |
| 223 | + GFP_KERNEL | __GFP_ZERO); |
| 224 | + if (!shm->kaddr) |
| 225 | + return -ENOMEM; |
| 226 | + |
| 227 | + shm->paddr = virt_to_phys(shm->kaddr); |
| 228 | + shm->size = nr_pages * PAGE_SIZE; |
| 229 | + |
| 230 | + pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); |
| 231 | + if (!pages) { |
| 232 | + rc = -ENOMEM; |
| 233 | + goto err; |
| 234 | + } |
| 235 | + |
| 236 | + for (i = 0; i < nr_pages; i++) |
| 237 | + pages[i] = virt_to_page((u8 *)shm->kaddr + i * PAGE_SIZE); |
| 238 | + |
| 239 | + shm->pages = pages; |
| 240 | + shm->num_pages = nr_pages; |
| 241 | + |
| 242 | + if (shm_register) { |
| 243 | + rc = shm_register(shm->ctx, shm, pages, nr_pages, |
| 244 | + (unsigned long)shm->kaddr); |
| 245 | + if (rc) |
| 246 | + goto err; |
| 247 | + } |
| 248 | + |
| 249 | + return 0; |
| 250 | +err: |
| 251 | + free_pages_exact(shm->kaddr, shm->size); |
| 252 | + shm->kaddr = NULL; |
| 253 | + return rc; |
| 254 | +} |
| 255 | +EXPORT_SYMBOL_GPL(tee_dyn_shm_alloc_helper); |
| 256 | + |
| 257 | +void tee_dyn_shm_free_helper(struct tee_shm *shm, |
| 258 | + int (*shm_unregister)(struct tee_context *ctx, |
| 259 | + struct tee_shm *shm)) |
| 260 | +{ |
| 261 | + if (shm_unregister) |
| 262 | + shm_unregister(shm->ctx, shm); |
| 263 | + free_pages_exact(shm->kaddr, shm->size); |
| 264 | + shm->kaddr = NULL; |
| 265 | + kfree(shm->pages); |
| 266 | + shm->pages = NULL; |
| 267 | +} |
| 268 | +EXPORT_SYMBOL_GPL(tee_dyn_shm_free_helper); |
| 269 | + |
205 | 270 | static struct tee_shm * |
206 | 271 | register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags, |
207 | 272 | int id) |
|
0 commit comments