L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
part_device.h
1/*
2 * Copyright (C) 2018-2022, 2024 Kernkonzept GmbH.
3 * Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
4 *
5 * License: see LICENSE.spdx (in this directory or the directories above)
6 */
7#pragma once
8
9#include <l4/cxx/ref_ptr>
10
11#include <l4/libblock-device/device.h>
12#include <l4/libblock-device/partition.h>
13
14#include <string>
15#include <locale>
16#include <codecvt>
17
18namespace Block_device {
19
20namespace Impl {
21
26 template <typename PART_DEV, typename BASE_DEV,
27 bool = std::is_base_of<Device_discard_feature, BASE_DEV>::value>
28 class Partitioned_device_discard_mixin : public BASE_DEV {};
29
36 template <typename PART_DEV, typename BASE_DEV>
37 class Partitioned_device_discard_mixin<PART_DEV, BASE_DEV, true>
38 : public BASE_DEV
39 {
40 using Base = BASE_DEV;
41 using Part_device = PART_DEV;
42
43 public:
44 typename Base::Discard_info discard_info() const override
45 {
46 return dev()->parent()->discard_info();
47 }
48
49 int discard(l4_uint64_t offset, Inout_block const &blocks,
50 Inout_callback const &cb, bool discard) override
51 {
52 auto sz = dev()->partition_size();
53
54 if (offset > sz)
55 return -L4_EINVAL;
56
57 Inout_block const *cur = &blocks;
58 while (cur)
59 {
60 if (cur->sector >= sz - offset)
61 return -L4_EINVAL;
62 if (cur->num_sectors > sz)
63 return -L4_EINVAL;
64 if (offset + cur->sector > sz - cur->num_sectors)
65 return -L4_EINVAL;
66
67 cur = cur->next.get();
68 }
69
70 auto start = offset + dev()->partition_start();
71 Dbg::trace("partition")
72 .printf("Starting sector on disk: 0x%llx\n", start);
73 return dev()->parent()->discard(start, blocks, cb, discard);
74 }
75
76 private:
77 Part_device const *dev() const
78 { return static_cast<Part_device const *>(this); }
79 };
80
81}
82
90template <typename BASE_DEV = Device>
92: public Impl::Partitioned_device_discard_mixin<Partitioned_device<BASE_DEV>, BASE_DEV>
93{
94public:
95 using Device_type = BASE_DEV;
96
98 unsigned partition_id, Partition_info const &pi)
99 : _name(pi.name),
100 _parent(dev),
101 _start(pi.first),
102 _size(pi.last - pi.first + 1)
103 {
104 if (pi.last < pi.first)
106 "Last sector of partition before first sector.");
107
108 if (partition_id > 999)
110 "Partition ID must be smaller than 1000.");
111
112 snprintf(_partition_id, sizeof(_partition_id), "%d", partition_id);
113
114 static_assert(sizeof(_guid) == sizeof(pi.guid), "String size mismatch");
115 memcpy(_guid, pi.guid, sizeof(_guid));
116 }
117
118 Notification_domain const *notification_domain() const override
119 { return _parent->notification_domain(); }
120
121 bool is_read_only() const override
122 { return _parent->is_read_only(); }
123
124 bool match_hid(cxx::String const &hid) const override
125 {
126 if (hid == cxx::String(_guid, 36))
127 return true;
128
129 _Pragma("GCC diagnostic push");
130 _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
131 std::u16string whid =
132 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
133 .from_bytes(std::string(hid.start(), hid.len()));
134 _Pragma("GCC diagnostic pop");
135 if (whid == _name)
136 return true;
137
138 // check for identifier of form: <device_name>:<partition id>
139 char const *delim = ":";
140 char const *pos = hid.rfind(delim);
141
142 if (pos == hid.end() || !_parent->match_hid(cxx::String(hid.start(), pos)))
143 return false;
144
145 return cxx::String(pos + 1, hid.end()) == cxx::String(_partition_id);
146 }
147
148 l4_uint64_t capacity() const override
149 { return _size * _parent->sector_size(); }
150
151 l4_size_t sector_size() const override
152 { return _parent->sector_size(); }
153
154 l4_size_t max_size() const override
155 { return _parent->max_size(); }
156
157 unsigned max_segments() const override
158 { return _parent->max_segments(); }
159
160 void reset() override
161 {}
162
163 int dma_map(Block_device::Mem_region *region, l4_addr_t offset,
164 l4_size_t num_sectors, L4Re::Dma_space::Direction dir,
165 L4Re::Dma_space::Dma_addr *phys) override
166 { return _parent->dma_map(region, offset, num_sectors, dir, phys); }
167
168 int dma_unmap(L4Re::Dma_space::Dma_addr phys, l4_size_t num_sectors,
169 L4Re::Dma_space::Direction dir) override
170 { return _parent->dma_unmap(phys, num_sectors, dir); }
171
172 int inout_data(l4_uint64_t sector, Inout_block const &blocks,
173 Inout_callback const &cb,
174 L4Re::Dma_space::Direction dir) override
175 {
176 if (sector >= _size)
177 return -L4_EINVAL;
178
179 l4_uint64_t total = 0;
180 Inout_block const *cur = &blocks;
181 while (cur)
182 {
183 total += cur->num_sectors;
184 cur = cur->next.get();
185 }
186
187 if (total > _size - sector)
188 return -L4_EINVAL;
189
190 Dbg::trace("partition").printf("Sector on disk: 0x%llx\n", sector + _start);
191 return _parent->inout_data(sector + _start, blocks, cb, dir);
192 }
193
194 int flush(Inout_callback const &cb) override
195 {
196 return _parent->flush(cb);
197 }
198
199 void start_device_scan(Block_device::Errand::Callback const &callback) override
200 { callback(); }
201
202 l4_uint64_t partition_size() const
203 { return _size; }
204
205 l4_uint64_t partition_start() const
206 { return _start; }
207
208 Device_type *parent() const
209 { return _parent.get(); }
210
211
212private:
213 char _guid[37];
214 std::u16string _name;
215 char _partition_id[4];
217 l4_uint64_t _start;
218 l4_uint64_t _size;
219};
220
221} // name space
Dummy class used when the device class is not derived from Device_discard_feature.
Definition part_device.h:28
A partition device for the given device interface.
Definition part_device.h:93
l4_uint64_t Dma_addr
Data type for DMA addresses.
Definition dma_space:59
Direction
Direction of the DMA transfers.
Definition dma_space:65
Region of driver memory, that shall be managed locally.
Definition l4virtio:451
A reference-counting pointer with automatic cleanup.
Definition ref_ptr:71
T * get() const noexcept
Return a raw pointer to the object this shared pointer points to.
Definition ref_ptr:121
Allocation free string class with explicit length field.
Definition string:31
Index start() const
Pointer to first character.
Definition string:54
Index end() const
Pointer to first byte behind the string.
Definition string:56
char const * rfind(char const *c) const
Find right-most character. Return end() if not found.
Definition string:132
int len() const
Length.
Definition string:58
unsigned int l4_size_t
Unsigned size type.
Definition l4int.h:24
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:31
@ L4_EINVAL
Invalid argument.
Definition err.h:46
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Definition error_helper:72
Description of an inout block to be sent to the device.
Definition types.h:67
l4_uint64_t sector
Initial sector. Used only by DISCARD / WRITE_ZEROES requests.
Definition types.h:71
Opaque type for representing a notification domain.
Definition device.h:33
Information about a single partition.
Definition partition.h:30
char guid[37]
ID of the partition.
Definition partition.h:31
l4_uint64_t last
Last valid sector.
Definition partition.h:34
l4_uint64_t first
First valid sector.
Definition partition.h:33
std::u16string name
UTF16 name of the partition.
Definition partition.h:32