coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
region.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <commonlib/helpers.h>
4 #include <commonlib/region.h>
5 #include <string.h>
6 
7 int region_is_subregion(const struct region *p, const struct region *c)
8 {
9  if (region_offset(c) < region_offset(p))
10  return 0;
11 
12  if (region_end(c) > region_end(p))
13  return 0;
14 
15  if (region_end(c) < region_offset(c))
16  return 0;
17 
18  return 1;
19 }
20 
21 static int normalize_and_ok(const struct region *outer, struct region *inner)
22 {
23  inner->offset += region_offset(outer);
24  return region_is_subregion(outer, inner);
25 }
26 
27 static const struct region_device *rdev_root(const struct region_device *rdev)
28 {
29  if (rdev->root == NULL)
30  return rdev;
31  return rdev->root;
32 }
33 
35  const struct region_device *c)
36 {
37  if (rdev_root(p) != rdev_root(c))
38  return -1;
39 
40  if (!region_is_subregion(&p->region, &c->region))
41  return -1;
42 
44 }
45 
46 void *rdev_mmap(const struct region_device *rd, size_t offset, size_t size)
47 {
48  const struct region_device *rdev;
49  struct region req = {
50  .offset = offset,
51  .size = size,
52  };
53 
54  if (!normalize_and_ok(&rd->region, &req))
55  return NULL;
56 
57  rdev = rdev_root(rd);
58 
59  if (rdev->ops->mmap == NULL)
60  return NULL;
61 
62  return rdev->ops->mmap(rdev, req.offset, req.size);
63 }
64 
65 int rdev_munmap(const struct region_device *rd, void *mapping)
66 {
67  const struct region_device *rdev;
68 
69  rdev = rdev_root(rd);
70 
71  if (rdev->ops->munmap == NULL)
72  return -1;
73 
74  return rdev->ops->munmap(rdev, mapping);
75 }
76 
77 ssize_t rdev_readat(const struct region_device *rd, void *b, size_t offset,
78  size_t size)
79 {
80  const struct region_device *rdev;
81  struct region req = {
82  .offset = offset,
83  .size = size,
84  };
85 
86  if (!normalize_and_ok(&rd->region, &req))
87  return -1;
88 
89  rdev = rdev_root(rd);
90 
91  return rdev->ops->readat(rdev, b, req.offset, req.size);
92 }
93 
94 ssize_t rdev_writeat(const struct region_device *rd, const void *b,
95  size_t offset, size_t size)
96 {
97  const struct region_device *rdev;
98  struct region req = {
99  .offset = offset,
100  .size = size,
101  };
102 
103  if (!normalize_and_ok(&rd->region, &req))
104  return -1;
105 
106  rdev = rdev_root(rd);
107 
108  if (rdev->ops->writeat == NULL)
109  return -1;
110 
111  return rdev->ops->writeat(rdev, b, req.offset, req.size);
112 }
113 
114 ssize_t rdev_eraseat(const struct region_device *rd, size_t offset,
115  size_t size)
116 {
117  const struct region_device *rdev;
118  struct region req = {
119  .offset = offset,
120  .size = size,
121  };
122 
123  if (!normalize_and_ok(&rd->region, &req))
124  return -1;
125 
126  rdev = rdev_root(rd);
127 
128  /* If the eraseat ptr is NULL we assume that the erase
129  * function was completed successfully. */
130  if (rdev->ops->eraseat == NULL)
131  return size;
132 
133  return rdev->ops->eraseat(rdev, req.offset, req.size);
134 }
135 
136 int rdev_chain(struct region_device *child, const struct region_device *parent,
137  size_t offset, size_t size)
138 {
139  struct region req = {
140  .offset = offset,
141  .size = size,
142  };
143 
144  if (!normalize_and_ok(&parent->region, &req))
145  return -1;
146 
147  /* Keep track of root region device. Note the offsets are relative
148  * to the root device. */
149  child->root = rdev_root(parent);
150  child->ops = NULL;
151  child->region.offset = req.offset;
152  child->region.size = req.size;
153 
154  return 0;
155 }
156 
158  const struct region_device_ops *ops, void *base, size_t size)
159 {
160  memset(mdev, 0, sizeof(*mdev));
161  mdev->base = base;
162  mdev->rdev.ops = ops;
163  mdev->rdev.region.size = size;
164 }
165 
167  size_t size)
168 {
170 }
171 
173  size_t size)
174 {
176 }
177 
179  const struct region_device_ops *ops, size_t offset,
180  size_t size)
181 {
182  memset(rdev, 0, sizeof(*rdev));
183  rdev->root = NULL;
184  rdev->ops = ops;
186  rdev->region.size = size;
187 }
188 
190  const struct region_device_ops *ops,
191  size_t window_count, const struct xlate_window *window_arr,
192  size_t parent_size)
193 {
194  memset(xdev, 0, sizeof(*xdev));
195  xdev->window_count = window_count;
196  xdev->window_arr = window_arr;
197  region_device_init(&xdev->rdev, ops, 0, parent_size);
198 }
199 
201  size_t window_count, const struct xlate_window *window_arr,
202  size_t parent_size)
203 {
204  xlate_region_device_init(xdev, &xlate_rdev_ro_ops, window_count, window_arr,
205  parent_size);
206 }
207 
209  size_t window_count, const struct xlate_window *window_arr,
210  size_t parent_size)
211 {
212  xlate_region_device_init(xdev, &xlate_rdev_rw_ops, window_count, window_arr,
213  parent_size);
214 }
215 
216 void xlate_window_init(struct xlate_window *window, const struct region_device *access_dev,
217  size_t sub_region_offset, size_t sub_region_size)
218 {
219  window->access_dev = access_dev;
220  window->sub_region.offset = sub_region_offset;
221  window->sub_region.size = sub_region_size;
222 }
223 
224 static void *mdev_mmap(const struct region_device *rd, size_t offset,
225  size_t size __unused)
226 {
227  const struct mem_region_device *mdev;
228 
229  mdev = container_of(rd, __typeof__(*mdev), rdev);
230 
231  return &mdev->base[offset];
232 }
233 
234 static int mdev_munmap(const struct region_device *rd __unused,
235  void *mapping __unused)
236 {
237  return 0;
238 }
239 
240 static ssize_t mdev_readat(const struct region_device *rd, void *b,
241  size_t offset, size_t size)
242 {
243  const struct mem_region_device *mdev;
244 
245  mdev = container_of(rd, __typeof__(*mdev), rdev);
246 
247  memcpy(b, &mdev->base[offset], size);
248 
249  return size;
250 }
251 
252 static ssize_t mdev_writeat(const struct region_device *rd, const void *b,
253  size_t offset, size_t size)
254 {
255  const struct mem_region_device *mdev;
256 
257  mdev = container_of(rd, __typeof__(*mdev), rdev);
258 
259  memcpy(&mdev->base[offset], b, size);
260 
261  return size;
262 }
263 
264 static ssize_t mdev_eraseat(const struct region_device *rd, size_t offset,
265  size_t size)
266 {
267  const struct mem_region_device *mdev;
268 
269  mdev = container_of(rd, __typeof__(*mdev), rdev);
270 
271  memset(&mdev->base[offset], 0, size);
272 
273  return size;
274 }
275 
276 const struct region_device_ops mem_rdev_ro_ops = {
277  .mmap = mdev_mmap,
278  .munmap = mdev_munmap,
279  .readat = mdev_readat,
280 };
281 
282 const struct region_device_ops mem_rdev_rw_ops = {
283  .mmap = mdev_mmap,
284  .munmap = mdev_munmap,
285  .readat = mdev_readat,
286  .writeat = mdev_writeat,
287  .eraseat = mdev_eraseat,
288 };
289 
290 static const struct mem_region_device mem_rdev = MEM_REGION_DEV_RO_INIT(0, ~(size_t)0);
291 static const struct mem_region_device mem_rdev_rw = MEM_REGION_DEV_RW_INIT(0, ~(size_t)0);
292 
293 int rdev_chain_mem(struct region_device *child, const void *base, size_t size)
294 {
295  return rdev_chain(child, &mem_rdev.rdev, (uintptr_t)base, size);
296 }
297 
298 int rdev_chain_mem_rw(struct region_device *child, void *base, size_t size)
299 {
300  return rdev_chain(child, &mem_rdev_rw.rdev, (uintptr_t)base, size);
301 }
302 
303 void *mmap_helper_rdev_mmap(const struct region_device *rd, size_t offset,
304  size_t size)
305 {
307  void *mapping;
308 
309  mdev = container_of((void *)rd, __typeof__(*mdev), rdev);
310 
311  mapping = mem_pool_alloc(mdev->pool, size);
312 
313  if (mapping == NULL)
314  return NULL;
315 
316  if (rd->ops->readat(rd, mapping, offset, size) != size) {
317  mem_pool_free(mdev->pool, mapping);
318  return NULL;
319  }
320 
321  return mapping;
322 }
323 
324 int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
325 {
327 
328  mdev = container_of((void *)rd, __typeof__(*mdev), rdev);
329 
330  mem_pool_free(mdev->pool, mapping);
331 
332  return 0;
333 }
334 
335 static const struct xlate_window *xlate_find_window(const struct xlate_region_device *xldev,
336  const struct region *req)
337 {
338  size_t i;
339  const struct xlate_window *xlwindow;
340 
341  for (i = 0; i < xldev->window_count; i++) {
342  xlwindow = &xldev->window_arr[i];
343  if (region_is_subregion(&xlwindow->sub_region, req))
344  return xlwindow;
345  }
346 
347  return NULL;
348 }
349 
350 static void *xlate_mmap(const struct region_device *rd, size_t offset,
351  size_t size)
352 {
353  const struct xlate_region_device *xldev;
354  struct region req = {
355  .offset = offset,
356  .size = size,
357  };
358  const struct xlate_window *xlwindow;
359 
360  xldev = container_of(rd, __typeof__(*xldev), rdev);
361 
362  xlwindow = xlate_find_window(xldev, &req);
363  if (!xlwindow)
364  return NULL;
365 
366  offset -= region_offset(&xlwindow->sub_region);
367 
368  return rdev_mmap(xlwindow->access_dev, offset, size);
369 }
370 
371 static int xlate_munmap(const struct region_device *rd __unused, void *mapping __unused)
372 {
373  /*
374  * xlate_region_device does not keep track of the access device that was used to service
375  * a mmap request. So, munmap does not do anything. If munmap functionality is required,
376  * then xlate_region_device will have to be updated to accept some pre-allocated space
377  * from caller to keep track of the mapping requests. Since xlate_region_device is only
378  * used for memory mapped boot media on the backend right now, skipping munmap is fine.
379  */
380  return 0;
381 }
382 
383 static ssize_t xlate_readat(const struct region_device *rd, void *b,
384  size_t offset, size_t size)
385 {
386  struct region req = {
387  .offset = offset,
388  .size = size,
389  };
390  const struct xlate_window *xlwindow;
391  const struct xlate_region_device *xldev;
392 
393  xldev = container_of(rd, __typeof__(*xldev), rdev);
394 
395  xlwindow = xlate_find_window(xldev, &req);
396  if (!xlwindow)
397  return -1;
398 
399  offset -= region_offset(&xlwindow->sub_region);
400 
401  return rdev_readat(xlwindow->access_dev, b, offset, size);
402 }
403 
404 static ssize_t xlate_writeat(const struct region_device *rd, const void *b,
405  size_t offset, size_t size)
406 {
407  struct region req = {
408  .offset = offset,
409  .size = size,
410  };
411  const struct xlate_window *xlwindow;
412  const struct xlate_region_device *xldev;
413 
414  xldev = container_of(rd, __typeof__(*xldev), rdev);
415 
416  xlwindow = xlate_find_window(xldev, &req);
417  if (!xlwindow)
418  return -1;
419 
420  offset -= region_offset(&xlwindow->sub_region);
421 
422  return rdev_writeat(xlwindow->access_dev, b, offset, size);
423 }
424 
425 static ssize_t xlate_eraseat(const struct region_device *rd,
426  size_t offset, size_t size)
427 {
428  struct region req = {
429  .offset = offset,
430  .size = size,
431  };
432  const struct xlate_window *xlwindow;
433  const struct xlate_region_device *xldev;
434 
435  xldev = container_of(rd, __typeof__(*xldev), rdev);
436 
437  xlwindow = xlate_find_window(xldev, &req);
438  if (!xlwindow)
439  return -1;
440 
441  offset -= region_offset(&xlwindow->sub_region);
442 
443  return rdev_eraseat(xlwindow->access_dev, offset, size);
444 }
445 
446 const struct region_device_ops xlate_rdev_ro_ops = {
447  .mmap = xlate_mmap,
448  .munmap = xlate_munmap,
449  .readat = xlate_readat,
450 };
451 
452 const struct region_device_ops xlate_rdev_rw_ops = {
453  .mmap = xlate_mmap,
454  .munmap = xlate_munmap,
455  .readat = xlate_readat,
456  .writeat = xlate_writeat,
457  .eraseat = xlate_eraseat,
458 };
459 
460 static void *incoherent_mmap(const struct region_device *rd, size_t offset,
461  size_t size)
462 {
463  const struct incoherent_rdev *irdev;
464 
465  irdev = container_of(rd, const struct incoherent_rdev, rdev);
466 
467  return rdev_mmap(irdev->read, offset, size);
468 }
469 
470 static int incoherent_munmap(const struct region_device *rd, void *mapping)
471 {
472  const struct incoherent_rdev *irdev;
473 
474  irdev = container_of(rd, const struct incoherent_rdev, rdev);
475 
476  return rdev_munmap(irdev->read, mapping);
477 }
478 
479 static ssize_t incoherent_readat(const struct region_device *rd, void *b,
480  size_t offset, size_t size)
481 {
482  const struct incoherent_rdev *irdev;
483 
484  irdev = container_of(rd, const struct incoherent_rdev, rdev);
485 
486  return rdev_readat(irdev->read, b, offset, size);
487 }
488 
489 static ssize_t incoherent_writeat(const struct region_device *rd, const void *b,
490  size_t offset, size_t size)
491 {
492  const struct incoherent_rdev *irdev;
493 
494  irdev = container_of(rd, const struct incoherent_rdev, rdev);
495 
496  return rdev_writeat(irdev->write, b, offset, size);
497 }
498 
499 static ssize_t incoherent_eraseat(const struct region_device *rd, size_t offset,
500  size_t size)
501 {
502  const struct incoherent_rdev *irdev;
503 
504  irdev = container_of(rd, const struct incoherent_rdev, rdev);
505 
506  return rdev_eraseat(irdev->write, offset, size);
507 }
508 
509 static const struct region_device_ops incoherent_rdev_ops = {
511  .munmap = incoherent_munmap,
512  .readat = incoherent_readat,
513  .writeat = incoherent_writeat,
514  .eraseat = incoherent_eraseat,
515 };
516 
518  const struct region *r,
519  const struct region_device *read,
520  const struct region_device *write)
521 {
522  const size_t size = region_sz(r);
523 
524  if (size != region_device_sz(read) || size != region_device_sz(write))
525  return NULL;
526 
527  /* The region is represented as offset 0 to size. That way, the generic
528  * rdev operations can be called on the read or write implementation
529  * without any unnecessary translation because the offsets all start
530  * at 0. */
531  region_device_init(&irdev->rdev, &incoherent_rdev_ops, 0, size);
532  irdev->read = read;
533  irdev->write = write;
534 
535  return &irdev->rdev;
536 }
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
static struct mmap_helper_region_device mdev
Definition: cbfs_spi.c:79
static struct region_device rdev
Definition: flashconsole.c:14
static size_t offset
Definition: flashconsole.c:16
#define __unused
Definition: helpers.h:38
#define container_of(ptr, type, member)
container_of - cast a member of a structure out to the containing structure
Definition: helpers.h:33
static struct device_operations ops
Definition: ipmi_kcs_ops.c:416
void * mem_pool_alloc(struct mem_pool *mp, size_t sz)
Definition: mem_pool.c:6
void mem_pool_free(struct mem_pool *mp, void *alloc)
Definition: mem_pool.c:29
ssize_t rdev_eraseat(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:114
static const struct region_device * rdev_root(const struct region_device *rdev)
Definition: region.c:27
ssize_t rdev_relative_offset(const struct region_device *p, const struct region_device *c)
Definition: region.c:34
int rdev_munmap(const struct region_device *rd, void *mapping)
Definition: region.c:65
static ssize_t xlate_writeat(const struct region_device *rd, const void *b, size_t offset, size_t size)
Definition: region.c:404
static const struct xlate_window * xlate_find_window(const struct xlate_region_device *xldev, const struct region *req)
Definition: region.c:335
static void * incoherent_mmap(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:460
int region_is_subregion(const struct region *p, const struct region *c)
Definition: region.c:7
int rdev_chain_mem(struct region_device *child, const void *base, size_t size)
Definition: region.c:293
static void mem_region_device_init(struct mem_region_device *mdev, const struct region_device_ops *ops, void *base, size_t size)
Definition: region.c:157
static ssize_t mdev_writeat(const struct region_device *rd, const void *b, size_t offset, size_t size)
Definition: region.c:252
static int mdev_munmap(const struct region_device *rd __unused, void *mapping __unused)
Definition: region.c:234
const struct region_device_ops mem_rdev_rw_ops
Definition: region.c:282
ssize_t rdev_writeat(const struct region_device *rd, const void *b, size_t offset, size_t size)
Definition: region.c:94
static void xlate_region_device_init(struct xlate_region_device *xdev, const struct region_device_ops *ops, size_t window_count, const struct xlate_window *window_arr, size_t parent_size)
Definition: region.c:189
static const struct region_device_ops incoherent_rdev_ops
Definition: region.c:509
static ssize_t xlate_eraseat(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:425
static const struct mem_region_device mem_rdev
Definition: region.c:290
void xlate_window_init(struct xlate_window *window, const struct region_device *access_dev, size_t sub_region_offset, size_t sub_region_size)
Definition: region.c:216
static ssize_t xlate_readat(const struct region_device *rd, void *b, size_t offset, size_t size)
Definition: region.c:383
void * mmap_helper_rdev_mmap(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:303
void mem_region_device_ro_init(struct mem_region_device *mdev, void *base, size_t size)
Definition: region.c:166
const struct region_device_ops xlate_rdev_rw_ops
Definition: region.c:452
void * rdev_mmap(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:46
int rdev_chain_mem_rw(struct region_device *child, void *base, size_t size)
Definition: region.c:298
void xlate_region_device_rw_init(struct xlate_region_device *xdev, size_t window_count, const struct xlate_window *window_arr, size_t parent_size)
Definition: region.c:208
static ssize_t mdev_readat(const struct region_device *rd, void *b, size_t offset, size_t size)
Definition: region.c:240
static ssize_t incoherent_writeat(const struct region_device *rd, const void *b, size_t offset, size_t size)
Definition: region.c:489
void mem_region_device_rw_init(struct mem_region_device *mdev, void *base, size_t size)
Definition: region.c:172
static void * xlate_mmap(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:350
int rdev_chain(struct region_device *child, const struct region_device *parent, size_t offset, size_t size)
Definition: region.c:136
void region_device_init(struct region_device *rdev, const struct region_device_ops *ops, size_t offset, size_t size)
Definition: region.c:178
const struct region_device_ops xlate_rdev_ro_ops
Definition: region.c:446
int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
Definition: region.c:324
const struct region_device_ops mem_rdev_ro_ops
Definition: region.c:276
void xlate_region_device_ro_init(struct xlate_region_device *xdev, size_t window_count, const struct xlate_window *window_arr, size_t parent_size)
Definition: region.c:200
ssize_t rdev_readat(const struct region_device *rd, void *b, size_t offset, size_t size)
Definition: region.c:77
static void * mdev_mmap(const struct region_device *rd, size_t offset, size_t size __unused)
Definition: region.c:224
static int xlate_munmap(const struct region_device *rd __unused, void *mapping __unused)
Definition: region.c:371
static ssize_t incoherent_readat(const struct region_device *rd, void *b, size_t offset, size_t size)
Definition: region.c:479
const struct region_device * incoherent_rdev_init(struct incoherent_rdev *irdev, const struct region *r, const struct region_device *read, const struct region_device *write)
Definition: region.c:517
static const struct mem_region_device mem_rdev_rw
Definition: region.c:291
static int normalize_and_ok(const struct region *outer, struct region *inner)
Definition: region.c:21
static int incoherent_munmap(const struct region_device *rd, void *mapping)
Definition: region.c:470
static ssize_t incoherent_eraseat(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:499
static ssize_t mdev_eraseat(const struct region_device *rd, size_t offset, size_t size)
Definition: region.c:264
static size_t region_sz(const struct region *r)
Definition: region.h:110
static size_t region_device_sz(const struct region_device *rdev)
Definition: region.h:132
#define MEM_REGION_DEV_RW_INIT(base_, size_)
Definition: region.h:211
#define MEM_REGION_DEV_RO_INIT(base_, size_)
Definition: region.h:208
static size_t region_end(const struct region *r)
Definition: region.h:115
static size_t region_offset(const struct region *r)
Definition: region.h:105
static size_t region_device_offset(const struct region_device *rdev)
Definition: region.h:137
uintptr_t base
Definition: uart.c:17
#define NULL
Definition: stddef.h:19
__SIZE_TYPE__ ssize_t
Definition: stddef.h:13
unsigned long uintptr_t
Definition: stdint.h:21
const struct region_device * write
Definition: region.h:294
const struct region_device * read
Definition: region.h:293
struct region_device rdev
Definition: region.h:292
struct region_device rdev
Definition: region.h:184
struct mem_pool * pool
Definition: region.h:215
struct region_device rdev
Definition: region.h:216
ssize_t(* eraseat)(const struct region_device *, size_t, size_t)
Definition: region.h:73
ssize_t(* readat)(const struct region_device *, void *, size_t, size_t)
Definition: region.h:70
void *(* mmap)(const struct region_device *, size_t, size_t)
Definition: region.h:68
int(* munmap)(const struct region_device *, void *)
Definition: region.h:69
ssize_t(* writeat)(const struct region_device *, const void *, size_t, size_t)
Definition: region.h:71
struct region region
Definition: region.h:84
const struct region_device * root
Definition: region.h:82
const struct region_device_ops * ops
Definition: region.h:83
Definition: region.h:76
size_t size
Definition: region.h:78
size_t offset
Definition: region.h:77
struct region_device rdev
Definition: region.h:255
size_t window_count
Definition: region.h:253
const struct xlate_window * window_arr
Definition: region.h:254
const struct region_device * access_dev
Definition: region.h:248
struct region sub_region
Definition: region.h:249
#define c(value, pmcreg, dst_bits)