L4Re Operating System Framework – Interface and Usage Documentation
Loading...
Searching...
No Matches
partition.h
1/*
2 * Copyright (C) 2018, 2020-2022 Kernkonzept GmbH.
3 * Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
4 *
5 * This file is distributed under the terms of the GNU General Public
6 * License, version 2. Please see the COPYING-GPL-2 file for details.
7 */
8#pragma once
9
10#include <cstring>
11#include <string>
12#include <cassert>
13
14#include <l4/cxx/ref_ptr>
15
16#include <l4/l4virtio/virtio_block.h>
17
18#include <l4/libblock-device/debug.h>
19#include <l4/libblock-device/errand.h>
20#include <l4/libblock-device/inout_memory.h>
21#include <l4/libblock-device/gpt.h>
22
23#include <l4/sys/cache.h>
24
25namespace Block_device {
26
38
39
43template <typename DEV>
44class Partition_reader : public cxx::Ref_obj
45{
46 enum
47 {
48 Max_partitions = 1024
49 };
50
51public:
52 using Device_type = DEV;
53
54 Partition_reader(Device_type *dev)
55 : _num_partitions(0),
56 _dev(dev),
58 {}
59
60 void read(Errand::Callback const &callback)
61 {
62 _num_partitions = 0;
63 _callback = callback;
64
65 // preparation: read the first two sectors
66 _db = _header.inout_block();
67 read_sectors(0, &Partition_reader::get_gpt);
68 }
69
70 l4_size_t table_size() const
71 { return _num_partitions; }
72
73 int get_partition(l4_size_t idx, Partition_info *inf) const
74 {
75 if (idx == 0 || idx > _num_partitions)
76 return -L4_ERANGE;
77
78 unsigned secsz = _dev->sector_size();
79 auto *header = _header.template get<Gpt::Header const>(secsz);
80
81 Gpt::Entry *e = _parray.template get<Gpt::Entry>((idx - 1) * header->entry_size);
82
83 if (*((l4_uint64_t *) &e->partition_guid) == 0ULL)
84 return -L4_ENODEV;
85
86 render_guid(e->partition_guid, inf->guid);
87
88 auto name =
89 std::u16string((char16_t *)e->name, sizeof(e->name) / sizeof(e->name[0]));
90 inf->name = name.substr(0, name.find((char16_t) 0));
91
92 inf->first = e->first;
93 inf->last = e->last;
94 inf->flags = e->flags;
95
96 auto info = Dbg::info();
97 if (info.is_active())
98 {
99 info.printf("%3zu: %10lld %10lld %5gMiB [%.37s]\n",
100 idx, e->first, e->last,
101 (e->last - e->first + 1.0) * secsz / (1 << 20),
102 inf->guid);
103
104 char buf[37];
105 info.printf(" : Type: %s\n", render_guid(e->type_guid, buf));
106 }
107
108 auto warn = Dbg::warn();
109 if (inf->last < inf->first)
110 {
111 warn.printf(
112 "Invalid settings of %3zu. Last lba before first lba. Will ignore.\n",
113 idx);
114 // Errors in the GPT shall not crash any service -- just ignore the
115 // corresponding partition.
116 return -L4_ENODEV;
117 }
118
119 return L4_EOK;
120 }
121
122private:
123 void invoke_callback()
124 {
125 assert(_callback);
126 _callback();
127 // Reset the callback to drop potential transitive self-references
128 _callback = nullptr;
129 }
130
131 void get_gpt(int error, l4_size_t)
132 {
133 _header.unmap();
134
135 if (error < 0)
136 {
137 // can't read from device, we are done
138 invoke_callback();
139 return;
140 }
141
142 // prepare reading of the table from disk
143 unsigned secsz = _dev->sector_size();
144 auto *header = _header.template get<Gpt::Header const>(secsz);
145
146 auto info = Dbg::info();
147 auto trace = Dbg::trace();
148
149 if (strncmp(header->signature, "EFI PART", 8) != 0)
150 {
151 info.printf("No GUID partition header found.\n");
152 invoke_callback();
153 return;
154 }
155
156 // XXX check CRC32 of header
157
158 info.printf("GUID partition header found with up to %d partitions.\n",
159 header->partition_array_size);
160 char buf[37];
161 info.printf("GUID: %s\n", render_guid(header->disk_guid, buf));
162 trace.printf("Header positions: %llx (Backup: %llx)\n",
163 header->current_lba, header->backup_lba);
164 trace.printf("First + last: %llx and %llx\n",
165 header->first_lba, header->last_lba);
166 trace.printf("Partition table at %llx\n",
167 header->partition_array_lba);
168 trace.printf("Size of a partition entry: %d\n",
169 header->entry_size);
170
171 info.printf("GUID partition header found with %d partitions.\n",
172 header->partition_array_size);
173
174 _num_partitions = cxx::min<l4_uint32_t>(header->partition_array_size,
175 Max_partitions);
176
177 l4_size_t arraysz = _num_partitions * header->entry_size;
178 l4_size_t numsec = (arraysz - 1 + secsz) / secsz;
179
181 trace.printf("Reading GPT table @ 0x%p\n", _parray.template get<void>(0));
182
183 _db = _parray.inout_block();
184 read_sectors(header->partition_array_lba, &Partition_reader::done_gpt);
185 }
186
187
188 void done_gpt(int error, l4_size_t)
189 {
190 _parray.unmap();
191
192 // XXX check CRC32 of table
193
194 if (error < 0)
195 _num_partitions = 0;
196
197 invoke_callback();
198 }
199
200 void read_sectors(l4_uint64_t sector,
201 void (Partition_reader::*func)(int, l4_size_t))
202 {
203 using namespace std::placeholders;
204 auto next = std::bind(func, this, _1, _2);
205
206 l4_addr_t vstart = (l4_addr_t)_db.virt_addr;
207 l4_addr_t vend = vstart + _db.num_sectors * _dev->sector_size();
208 l4_cache_inv_data(vstart, vend);
209
210 Errand::poll(10, 10000,
211 [=]()
212 {
213 int ret = _dev->inout_data(
214 sector, _db,
215 [next, vstart, vend](int error, l4_size_t size)
216 {
217 l4_cache_inv_data(vstart, vend);
218 next(error, size);
219 },
221 if (ret < 0 && ret != -L4_EBUSY)
222 invoke_callback();
223 return ret != -L4_EBUSY;
224 },
225 [=](bool ret) { if (!ret) invoke_callback(); }
226 );
227 }
228
229 static char const *render_guid(void const *guid_p, char buf[])
230 {
231 auto *p = static_cast<unsigned char const *>(guid_p);
232 snprintf(buf, 37,
233 "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
234 p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6],
235 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
236
237 return buf;
238 }
239
240 l4_size_t _num_partitions;
241 Inout_block _db;
242 Device_type *_dev;
245 Errand::Callback _callback;
246};
247
248
249
250}
Helper class that temporarily allocates memory that can be used for in/out operations with the device...
Partition table reader for block devices.
Definition partition.h:45
@ From_device
device writes to the memory
Definition dma_space:79
unsigned int l4_size_t
Unsigned size type.
Definition l4int.h:35
unsigned long l4_addr_t
Address type.
Definition l4int.h:45
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:42
int l4_cache_inv_data(unsigned long start, unsigned long end) L4_NOTHROW
Cache invalidate a range; might write back to PoC.
Definition cache.h:97
@ L4_ERANGE
Range error.
Definition err.h:58
@ L4_EBUSY
Object currently busy, try later.
Definition err.h:53
@ L4_ENODEV
No such thing.
Definition err.h:55
@ L4_EOK
Ok.
Definition err.h:43
Description of an inout block to be sent to the device.
Definition types.h:68
Information about a single partition.
Definition partition.h:31
l4_uint64_t flags
Additional flags, depending on partition type.
Definition partition.h:36
char guid[37]
ID of the partition.
Definition partition.h:32
l4_uint64_t last
Last valid sector.
Definition partition.h:35
l4_uint64_t first
First valid sector.
Definition partition.h:34
std::u16string name
UTF16 name of the partition.
Definition partition.h:33