1 /*
2  * Copyright (c) 2009 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #pragma once
9 
10 #include <assert.h>
11 #include <sys/types.h>
12 #include <lk/list.h>
13 
14 __BEGIN_CDECLS
15 
16 #define BIO_FLAGS_NONE                (0 << 0)
17 #define BIO_FLAG_CACHE_ALIGNED_READS  (1 << 0)
18 #define BIO_FLAG_CACHE_ALIGNED_WRITES (1 << 1)
19 
20 typedef uint32_t bnum_t;
21 
22 typedef struct bio_erase_geometry_info {
23     off_t  start;  // start of the region in bytes.
24     off_t  size;
25     size_t erase_size;
26     size_t erase_shift;
27 } bio_erase_geometry_info_t;
28 
29 typedef struct bdev {
30     struct list_node node;
31     volatile int ref;
32 
33     /* info about the block device */
34     char *name;
35     off_t total_size;
36 
37     size_t block_size;
38     size_t block_shift;
39     bnum_t block_count;
40 
41     size_t geometry_count;
42     const bio_erase_geometry_info_t *geometry;
43 
44     uint8_t erase_byte;
45 
46     uint32_t flags;
47 
48     /* function pointers */
49     ssize_t (*read)(struct bdev *, void *buf, off_t offset, size_t len);
50     ssize_t (*read_block)(struct bdev *, void *buf, bnum_t block, uint count);
51     ssize_t (*write)(struct bdev *, const void *buf, off_t offset, size_t len);
52     ssize_t (*write_block)(struct bdev *, const void *buf, bnum_t block, uint count);
53     ssize_t (*erase)(struct bdev *, off_t offset, size_t len);
54     int (*ioctl)(struct bdev *, int request, void *argp);
55     void (*close)(struct bdev *);
56 } bdev_t;
57 
58 /* user api */
59 bdev_t *bio_open(const char *name);
60 void bio_close(bdev_t *dev);
61 ssize_t bio_read(bdev_t *dev, void *buf, off_t offset, size_t len);
62 ssize_t bio_read_block(bdev_t *dev, void *buf, bnum_t block, uint count);
63 ssize_t bio_write(bdev_t *dev, const void *buf, off_t offset, size_t len);
64 ssize_t bio_write_block(bdev_t *dev, const void *buf, bnum_t block, uint count);
65 ssize_t bio_erase(bdev_t *dev, off_t offset, size_t len);
66 int bio_ioctl(bdev_t *dev, int request, void *argp);
67 
68 /* register a block device */
69 void bio_register_device(bdev_t *dev);
70 void bio_unregister_device(bdev_t *dev);
71 
72 /* used during bdev construction */
73 void bio_initialize_bdev(bdev_t *dev,
74                          const char *name,
75                          size_t block_size,
76                          bnum_t block_count,
77                          size_t geometry_count,
78                          const bio_erase_geometry_info_t *geometry,
79                          const uint32_t flags);
80 
81 /* debug stuff */
82 void bio_dump_devices(void);
83 
84 /* subdevice support */
85 status_t bio_publish_subdevice(const char *parent_dev,
86                                const char *subdev,
87                                bnum_t startblock,
88                                bnum_t block_count);
89 
90 /* memory based block device */
91 int create_membdev(const char *name, void *ptr, size_t len);
92 
93 /* helper routine to trim an offset + len to the device */
94 size_t bio_trim_range(const bdev_t *dev, off_t offset, size_t len);
95 
96 /* helper routine to trim to a block range in the device */
97 uint bio_trim_block_range(const bdev_t *dev, bnum_t block, uint count);
98 
99 /* utility routine */
bio_does_overlap(uint64_t start1,uint64_t len1,uint64_t start2,uint64_t len2)100 static inline bool bio_does_overlap(uint64_t start1, uint64_t len1,
101                                     uint64_t start2, uint64_t len2) {
102     uint64_t end1 = start1 + len1;
103     uint64_t end2 = start2 + len2;
104 
105     DEBUG_ASSERT(end1 >= start1);
106     DEBUG_ASSERT(end2 >= start2);
107 
108     return (((start1 >= start2) && (start1 < end2)) ||
109             ((start2 >= start1) && (start2 < end1)));
110 }
111 
bio_contains_range(uint64_t container_start,uint64_t container_len,uint64_t contained_start,uint64_t contained_len)112 static inline bool bio_contains_range(uint64_t container_start, uint64_t container_len,
113                                       uint64_t contained_start, uint64_t contained_len) {
114     uint64_t container_end = container_start + container_len;
115     uint64_t contained_end = contained_start + contained_len;
116 
117     DEBUG_ASSERT(container_end >= container_start);
118     DEBUG_ASSERT(contained_end >= contained_start);
119 
120     return ((container_start <= contained_start) &&
121             (container_end   >= contained_end));
122 }
123 
124 /* generic bio ioctls */
125 enum bio_ioctl_num {
126     BIO_IOCTL_NULL = 0,
127     BIO_IOCTL_GET_MEM_MAP,  /* if supported, request a pointer to the memory map of the device */
128     BIO_IOCTL_PUT_MEM_MAP,  /* if needed, return the pointer (to 'close' the map) */
129     BIO_IOCTL_GET_MAP_ADDR, /* if supported, request a pointer to the memory map without putting the device into linear mode */
130     BIO_IOCTL_IS_MAPPED,    /* if supported, returns whether or not the device is memory mapped. */
131 };
132 
133 __END_CDECLS