00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <unistd.h>
00049 #include <ipc/bd.h>
00050 #include <async.h>
00051 #include <as.h>
00052 #include <fibril_synch.h>
00053 #include <devmap.h>
00054 #include <sys/types.h>
00055 #include <sys/typefmt.h>
00056 #include <inttypes.h>
00057 #include <libblock.h>
00058 #include <devmap.h>
00059 #include <errno.h>
00060 #include <bool.h>
00061 #include <byteorder.h>
00062 #include <assert.h>
00063 #include <macros.h>
00064 #include <task.h>
00065
00066 #include "gpt.h"
00067
00068 #define NAME "guid_part"
00069
00070 const uint8_t efi_signature[8] = {
00071
00072 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
00073 };
00074
00076 typedef struct part {
00078 bool present;
00080 aoff64_t start_addr;
00082 aoff64_t length;
00084 devmap_handle_t dev;
00086 struct part *next;
00087 } part_t;
00088
00089 static size_t block_size;
00090
00092 static devmap_handle_t indev_handle;
00093
00095 static part_t plist_head;
00096
00097 static int gpt_init(const char *dev_name);
00098 static int gpt_read(void);
00099 static part_t *gpt_part_new(void);
00100 static void gpt_pte_to_part(const gpt_entry_t *pte, part_t *part);
00101 static void gpt_connection(ipc_callid_t iid, ipc_call_t *icall);
00102 static int gpt_bd_read(part_t *p, aoff64_t ba, size_t cnt, void *buf);
00103 static int gpt_bd_write(part_t *p, aoff64_t ba, size_t cnt, const void *buf);
00104 static int gpt_bsa_translate(part_t *p, aoff64_t ba, size_t cnt, aoff64_t *gba);
00105
00106 int main(int argc, char **argv)
00107 {
00108 printf(NAME ": GUID partition table driver\n");
00109
00110 if (argc != 2) {
00111 printf("Expected one argument (device name).\n");
00112 return -1;
00113 }
00114
00115 if (gpt_init(argv[1]) != EOK)
00116 return -1;
00117
00118 printf(NAME ": Accepting connections\n");
00119 task_retval(0);
00120 async_manager();
00121
00122
00123 return 0;
00124 }
00125
00126 static int gpt_init(const char *dev_name)
00127 {
00128 int rc;
00129 int i;
00130 char *name;
00131 devmap_handle_t dev;
00132 uint64_t size_mb;
00133 part_t *part;
00134
00135 rc = devmap_device_get_handle(dev_name, &indev_handle, 0);
00136 if (rc != EOK) {
00137 printf(NAME ": could not resolve device `%s'.\n", dev_name);
00138 return rc;
00139 }
00140
00141 rc = block_init(indev_handle, 2048);
00142 if (rc != EOK) {
00143 printf(NAME ": could not init libblock.\n");
00144 return rc;
00145 }
00146
00147
00148
00149 rc = block_get_bsize(indev_handle, &block_size);
00150 if (rc != EOK) {
00151 printf(NAME ": error getting block size.\n");
00152 return rc;
00153 }
00154
00155 if (block_size < 512 || (block_size % 512) != 0) {
00156 printf(NAME ": invalid block size %zu.\n", block_size);
00157 return ENOTSUP;
00158 }
00159
00160
00161 rc = gpt_read();
00162 if (rc != EOK)
00163 return rc;
00164
00165
00166 rc = devmap_driver_register(NAME, gpt_connection);
00167 if (rc != EOK) {
00168 printf(NAME ": Unable to register driver.\n");
00169 return rc;
00170 }
00171
00172
00173
00174
00175 i = 0;
00176 part = plist_head.next;
00177
00178 while (part != NULL) {
00179
00180 if (!part->present) {
00181 part = part->next;
00182 ++i;
00183 continue;
00184 }
00185
00186 asprintf(&name, "%sp%d", dev_name, i);
00187 if (name == NULL)
00188 return ENOMEM;
00189
00190 rc = devmap_device_register(name, &dev);
00191 if (rc != EOK) {
00192 printf(NAME ": Unable to register device %s.\n", name);
00193 return rc;
00194 }
00195
00196 size_mb = (part->length * block_size + 1024 * 1024 - 1)
00197 / (1024 * 1024);
00198 printf(NAME ": Registered device %s: %" PRIu64 " blocks "
00199 "%" PRIuOFF64 " MB.\n", name, part->length, size_mb);
00200
00201 part->dev = dev;
00202 free(name);
00203
00204 part = part->next;
00205 ++i;
00206 }
00207
00208 return EOK;
00209 }
00210
00212 static int gpt_read(void)
00213 {
00214 int i, rc;
00215 gpt_header_t *gpt_hdr;
00216 gpt_entry_t *etable;
00217 uint64_t ba;
00218 uint32_t bcnt;
00219 uint32_t esize;
00220 uint32_t num_entries;
00221 uint32_t entry;
00222 part_t *prev, *p;
00223
00224 gpt_hdr = malloc(block_size);
00225 if (gpt_hdr == NULL) {
00226 printf(NAME ": Failed allocating memory.\n");
00227 return ENOMEM;
00228 }
00229
00230 rc = block_read_direct(indev_handle, GPT_HDR_BA, 1, gpt_hdr);
00231 if (rc != EOK) {
00232 printf(NAME ": Failed reading GPT header block.\n");
00233 return rc;
00234 }
00235
00236 for (i = 0; i < 8; ++i) {
00237 if (gpt_hdr->efi_signature[i] != efi_signature[i]) {
00238 printf(NAME ": Invalid GPT signature.\n");
00239 return EINVAL;
00240 }
00241 }
00242
00243 plist_head.next = NULL;
00244 prev = &plist_head;
00245
00246 num_entries = uint32_t_le2host(gpt_hdr->num_entries);
00247 ba = uint64_t_le2host(gpt_hdr->entry_lba);
00248 esize = uint32_t_le2host(gpt_hdr->entry_size);
00249 bcnt = (num_entries / esize) + ((num_entries % esize != 0) ? 1 : 0);
00250
00251 etable = malloc(num_entries * esize);
00252 if (etable == NULL) {
00253 free(gpt_hdr);
00254 printf(NAME ": Failed allocating memory.\n");
00255 return ENOMEM;
00256 }
00257
00258 rc = block_read_direct(indev_handle, ba, bcnt, etable);
00259 if (rc != EOK) {
00260 printf(NAME ": Failed reading GPT entries.\n");
00261 return rc;
00262 }
00263
00264 for (entry = 0; entry < num_entries; ++entry) {
00265 p = gpt_part_new();
00266 if (p == NULL)
00267 return ENOMEM;
00268
00269 gpt_pte_to_part(&etable[entry], p);
00270 prev->next = p;
00271 prev = p;
00272 }
00273
00274 free(etable);
00275
00276 return EOK;
00277 }
00278
00280 static part_t *gpt_part_new(void)
00281 {
00282 return malloc(sizeof(part_t));
00283 }
00284
00286 static void gpt_pte_to_part(const gpt_entry_t *pte, part_t *part)
00287 {
00288 uint64_t sa, len;
00289 int i;
00290
00291
00292 sa = uint64_t_le2host(pte->start_lba);
00293 len = uint64_t_le2host(pte->end_lba) + 1 - sa;
00294
00295 part->start_addr = sa;
00296 part->length = len;
00297
00298 part->present = false;
00299
00300 for (i = 0; i < 8; ++i) {
00301 if (pte->part_type[i] != 0x00)
00302 part->present = true;
00303 }
00304
00305 part->dev = 0;
00306 part->next = NULL;
00307 }
00308
00309 static void gpt_connection(ipc_callid_t iid, ipc_call_t *icall)
00310 {
00311 size_t comm_size;
00312 void *fs_va = NULL;
00313 ipc_callid_t callid;
00314 ipc_call_t call;
00315 sysarg_t method;
00316 devmap_handle_t dh;
00317 unsigned int flags;
00318 int retval;
00319 aoff64_t ba;
00320 size_t cnt;
00321 part_t *part;
00322
00323
00324 dh = IPC_GET_ARG1(*icall);
00325
00326
00327
00328
00329
00330
00331 part = plist_head.next;
00332 while (part != NULL && part->dev != dh)
00333 part = part->next;
00334
00335 if (part == NULL) {
00336 async_answer_0(iid, EINVAL);
00337 return;
00338 }
00339
00340 assert(part->present == true);
00341
00342
00343 async_answer_0(iid, EOK);
00344
00345 if (!async_share_out_receive(&callid, &comm_size, &flags)) {
00346 async_answer_0(callid, EHANGUP);
00347 return;
00348 }
00349
00350 fs_va = as_get_mappable_page(comm_size);
00351 if (fs_va == NULL) {
00352 async_answer_0(callid, EHANGUP);
00353 return;
00354 }
00355
00356 (void) async_share_out_finalize(callid, fs_va);
00357
00358 while (1) {
00359 callid = async_get_call(&call);
00360 method = IPC_GET_IMETHOD(call);
00361 switch (method) {
00362 case IPC_M_PHONE_HUNGUP:
00363
00364 async_answer_0(callid, EOK);
00365 return;
00366 case BD_READ_BLOCKS:
00367 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00368 IPC_GET_ARG2(call));
00369 cnt = IPC_GET_ARG3(call);
00370 if (cnt * block_size > comm_size) {
00371 retval = ELIMIT;
00372 break;
00373 }
00374 retval = gpt_bd_read(part, ba, cnt, fs_va);
00375 break;
00376 case BD_WRITE_BLOCKS:
00377 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00378 IPC_GET_ARG2(call));
00379 cnt = IPC_GET_ARG3(call);
00380 if (cnt * block_size > comm_size) {
00381 retval = ELIMIT;
00382 break;
00383 }
00384 retval = gpt_bd_write(part, ba, cnt, fs_va);
00385 break;
00386 case BD_GET_BLOCK_SIZE:
00387 async_answer_1(callid, EOK, block_size);
00388 continue;
00389 case BD_GET_NUM_BLOCKS:
00390 async_answer_2(callid, EOK, LOWER32(part->length),
00391 UPPER32(part->length));
00392 continue;
00393 default:
00394 retval = EINVAL;
00395 break;
00396 }
00397 async_answer_0(callid, retval);
00398 }
00399 }
00400
00402 static int gpt_bd_read(part_t *p, aoff64_t ba, size_t cnt, void *buf)
00403 {
00404 aoff64_t gba;
00405
00406 if (gpt_bsa_translate(p, ba, cnt, &gba) != EOK)
00407 return ELIMIT;
00408
00409 return block_read_direct(indev_handle, gba, cnt, buf);
00410 }
00411
00413 static int gpt_bd_write(part_t *p, aoff64_t ba, size_t cnt, const void *buf)
00414 {
00415 aoff64_t gba;
00416
00417 if (gpt_bsa_translate(p, ba, cnt, &gba) != EOK)
00418 return ELIMIT;
00419
00420 return block_write_direct(indev_handle, gba, cnt, buf);
00421 }
00422
00424 static int gpt_bsa_translate(part_t *p, aoff64_t ba, size_t cnt, aoff64_t *gba)
00425 {
00426 if (ba + cnt > p->length)
00427 return ELIMIT;
00428
00429 *gba = p->start_addr + ba;
00430 return EOK;
00431 }
00432