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
00056 #include <stdio.h>
00057 #include <stdlib.h>
00058 #include <unistd.h>
00059 #include <ipc/bd.h>
00060 #include <async.h>
00061 #include <as.h>
00062 #include <fibril_synch.h>
00063 #include <devmap.h>
00064 #include <sys/types.h>
00065 #include <sys/typefmt.h>
00066 #include <inttypes.h>
00067 #include <libblock.h>
00068 #include <devmap.h>
00069 #include <errno.h>
00070 #include <bool.h>
00071 #include <byteorder.h>
00072 #include <assert.h>
00073 #include <macros.h>
00074 #include <task.h>
00075
00076 #define NAME "mbr_part"
00077
00078 enum {
00080 N_PRIMARY = 4,
00081
00083 BR_SIGNATURE = 0xAA55
00084 };
00085
00086 enum ptype {
00088 PT_UNUSED = 0x00,
00090 PT_EXTENDED = 0x05,
00091 };
00092
00094 typedef struct part {
00096 bool present;
00098 aoff64_t start_addr;
00100 aoff64_t length;
00102 devmap_handle_t dev;
00104 struct part *next;
00105 } part_t;
00106
00108 typedef struct {
00109 uint8_t status;
00111 uint8_t first_chs[3];
00113 uint8_t ptype;
00115 uint8_t last_chs[3];
00117 uint32_t first_lba;
00119 uint32_t length;
00120 } __attribute__((packed)) pt_entry_t;
00121
00123 typedef struct {
00124
00125 uint8_t code_area[440];
00126
00127
00128 uint32_t media_id;
00129
00130 uint16_t pad0;
00131
00133 pt_entry_t pte[N_PRIMARY];
00134
00136 uint16_t signature;
00137 } __attribute__((packed)) br_block_t;
00138
00139
00140 static size_t block_size;
00141
00143 static devmap_handle_t indev_handle;
00144
00146 static part_t plist_head;
00147
00148 static int mbr_init(const char *dev_name);
00149 static int mbr_part_read(void);
00150 static part_t *mbr_part_new(void);
00151 static void mbr_pte_to_part(uint32_t base, const pt_entry_t *pte, part_t *part);
00152 static void mbr_connection(ipc_callid_t iid, ipc_call_t *icall);
00153 static int mbr_bd_read(part_t *p, uint64_t ba, size_t cnt, void *buf);
00154 static int mbr_bd_write(part_t *p, uint64_t ba, size_t cnt, const void *buf);
00155 static int mbr_bsa_translate(part_t *p, uint64_t ba, size_t cnt, uint64_t *gba);
00156
00157 int main(int argc, char **argv)
00158 {
00159 printf(NAME ": PC MBR partition driver\n");
00160
00161 if (argc != 2) {
00162 printf("Expected one argument (device name).\n");
00163 return -1;
00164 }
00165
00166 if (mbr_init(argv[1]) != EOK)
00167 return -1;
00168
00169 printf(NAME ": Accepting connections\n");
00170 task_retval(0);
00171 async_manager();
00172
00173
00174 return 0;
00175 }
00176
00177 static int mbr_init(const char *dev_name)
00178 {
00179 int rc;
00180 int i;
00181 char *name;
00182 devmap_handle_t dev;
00183 uint64_t size_mb;
00184 part_t *part;
00185
00186 rc = devmap_device_get_handle(dev_name, &indev_handle, 0);
00187 if (rc != EOK) {
00188 printf(NAME ": could not resolve device `%s'.\n", dev_name);
00189 return rc;
00190 }
00191
00192 rc = block_init(indev_handle, 2048);
00193 if (rc != EOK) {
00194 printf(NAME ": could not init libblock.\n");
00195 return rc;
00196 }
00197
00198
00199
00200 rc = block_get_bsize(indev_handle, &block_size);
00201 if (rc != EOK) {
00202 printf(NAME ": error getting block size.\n");
00203 return rc;
00204 }
00205
00206 if (block_size < 512 || (block_size % 512) != 0) {
00207 printf(NAME ": invalid block size %zu.\n", block_size);
00208 return ENOTSUP;
00209 }
00210
00211
00212 rc = mbr_part_read();
00213 if (rc != EOK)
00214 return rc;
00215
00216
00217 rc = devmap_driver_register(NAME, mbr_connection);
00218 if (rc != EOK) {
00219 printf(NAME ": Unable to register driver.\n");
00220 return rc;
00221 }
00222
00223
00224
00225
00226 i = 0;
00227 part = plist_head.next;
00228
00229 while (part != NULL) {
00230
00231 if (!part->present) {
00232 part = part->next;
00233 ++i;
00234 continue;
00235 }
00236
00237 asprintf(&name, "%sp%d", dev_name, i);
00238 if (name == NULL)
00239 return ENOMEM;
00240
00241 rc = devmap_device_register(name, &dev);
00242 if (rc != EOK) {
00243 printf(NAME ": Unable to register device %s.\n", name);
00244 return rc;
00245 }
00246
00247 size_mb = (part->length * block_size + 1024 * 1024 - 1)
00248 / (1024 * 1024);
00249 printf(NAME ": Registered device %s: %" PRIuOFF64 " blocks "
00250 "%" PRIu64 " MB.\n", name, part->length, size_mb);
00251
00252 part->dev = dev;
00253 free(name);
00254
00255 part = part->next;
00256 ++i;
00257 }
00258
00259 return EOK;
00260 }
00261
00263 static int mbr_part_read(void)
00264 {
00265 int i, rc;
00266 br_block_t *brb;
00267 uint16_t sgn;
00268 uint32_t ba;
00269 part_t *ext_part, cp;
00270 uint32_t base;
00271 part_t *prev, *p;
00272
00273 brb = malloc(sizeof(br_block_t));
00274 if (brb == NULL) {
00275 printf(NAME ": Failed allocating memory.\n");
00276 return ENOMEM;
00277 }
00278
00279
00280
00281
00282
00283 rc = block_read_direct(indev_handle, 0, 1, brb);
00284 if (rc != EOK) {
00285 printf(NAME ": Failed reading MBR block.\n");
00286 return rc;
00287 }
00288
00289 sgn = uint16_t_le2host(brb->signature);
00290 if (sgn != BR_SIGNATURE) {
00291 printf(NAME ": Invalid boot record signature 0x%04" PRIX16
00292 ".\n", sgn);
00293 return EINVAL;
00294 }
00295
00296 ext_part = NULL;
00297 plist_head.next = NULL;
00298 prev = &plist_head;
00299
00300 for (i = 0; i < N_PRIMARY; ++i) {
00301 p = mbr_part_new();
00302 if (p == NULL)
00303 return ENOMEM;
00304
00305 mbr_pte_to_part(0, &brb->pte[i], p);
00306 prev->next = p;
00307 prev = p;
00308
00309 if (brb->pte[i].ptype == PT_EXTENDED) {
00310 p->present = false;
00311 ext_part = p;
00312 }
00313 }
00314
00315 if (ext_part == NULL)
00316 return EOK;
00317
00318 printf("Extended partition found.\n");
00319
00320
00321
00322
00323
00324 cp.start_addr = ext_part->start_addr;
00325 cp.length = ext_part->length;
00326 base = ext_part->start_addr;
00327
00328 do {
00329
00330
00331
00332
00333 ba = cp.start_addr;
00334 rc = block_read_direct(indev_handle, ba, 1, brb);
00335 if (rc != EOK) {
00336 printf(NAME ": Failed reading EBR block at %"
00337 PRIu32 ".\n", ba);
00338 return rc;
00339 }
00340
00341 sgn = uint16_t_le2host(brb->signature);
00342 if (sgn != BR_SIGNATURE) {
00343 printf(NAME ": Invalid boot record signature 0x%04"
00344 PRIX16 " in EBR at %" PRIu32 ".\n", sgn, ba);
00345 return EINVAL;
00346 }
00347
00348 p = mbr_part_new();
00349 if (p == NULL)
00350 return ENOMEM;
00351
00352
00353 mbr_pte_to_part(base, &brb->pte[0], p);
00354 prev->next = p;
00355 prev = p;
00356
00357
00358 mbr_pte_to_part(base, &brb->pte[1], &cp);
00359 } while (cp.present);
00360
00361 return EOK;
00362 }
00363
00365 static part_t *mbr_part_new(void)
00366 {
00367 return malloc(sizeof(part_t));
00368 }
00369
00371 static void mbr_pte_to_part(uint32_t base, const pt_entry_t *pte, part_t *part)
00372 {
00373 uint32_t sa, len;
00374
00375 sa = uint32_t_le2host(pte->first_lba);
00376 len = uint32_t_le2host(pte->length);
00377
00378 part->start_addr = base + sa;
00379 part->length = len;
00380
00381 part->present = (pte->ptype != PT_UNUSED) ? true : false;
00382
00383 part->dev = 0;
00384 part->next = NULL;
00385 }
00386
00387 static void mbr_connection(ipc_callid_t iid, ipc_call_t *icall)
00388 {
00389 size_t comm_size;
00390 void *fs_va = NULL;
00391 ipc_callid_t callid;
00392 ipc_call_t call;
00393 sysarg_t method;
00394 devmap_handle_t dh;
00395 unsigned int flags;
00396 int retval;
00397 uint64_t ba;
00398 size_t cnt;
00399 part_t *part;
00400
00401
00402 dh = IPC_GET_ARG1(*icall);
00403
00404
00405
00406
00407
00408
00409 part = plist_head.next;
00410 while (part != NULL && part->dev != dh)
00411 part = part->next;
00412
00413 if (part == NULL) {
00414 async_answer_0(iid, EINVAL);
00415 return;
00416 }
00417
00418 assert(part->present == true);
00419
00420
00421 async_answer_0(iid, EOK);
00422
00423 if (!async_share_out_receive(&callid, &comm_size, &flags)) {
00424 async_answer_0(callid, EHANGUP);
00425 return;
00426 }
00427
00428 fs_va = as_get_mappable_page(comm_size);
00429 if (fs_va == NULL) {
00430 async_answer_0(callid, EHANGUP);
00431 return;
00432 }
00433
00434 (void) async_share_out_finalize(callid, fs_va);
00435
00436 while (1) {
00437 callid = async_get_call(&call);
00438 method = IPC_GET_IMETHOD(call);
00439 switch (method) {
00440 case IPC_M_PHONE_HUNGUP:
00441
00442 async_answer_0(callid, EOK);
00443 return;
00444 case BD_READ_BLOCKS:
00445 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00446 IPC_GET_ARG2(call));
00447 cnt = IPC_GET_ARG3(call);
00448 if (cnt * block_size > comm_size) {
00449 retval = ELIMIT;
00450 break;
00451 }
00452 retval = mbr_bd_read(part, ba, cnt, fs_va);
00453 break;
00454 case BD_WRITE_BLOCKS:
00455 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00456 IPC_GET_ARG2(call));
00457 cnt = IPC_GET_ARG3(call);
00458 if (cnt * block_size > comm_size) {
00459 retval = ELIMIT;
00460 break;
00461 }
00462 retval = mbr_bd_write(part, ba, cnt, fs_va);
00463 break;
00464 case BD_GET_BLOCK_SIZE:
00465 async_answer_1(callid, EOK, block_size);
00466 continue;
00467 case BD_GET_NUM_BLOCKS:
00468 async_answer_2(callid, EOK, LOWER32(part->length),
00469 UPPER32(part->length));
00470 continue;
00471 default:
00472 retval = EINVAL;
00473 break;
00474 }
00475 async_answer_0(callid, retval);
00476 }
00477 }
00478
00480 static int mbr_bd_read(part_t *p, uint64_t ba, size_t cnt, void *buf)
00481 {
00482 uint64_t gba;
00483
00484 if (mbr_bsa_translate(p, ba, cnt, &gba) != EOK)
00485 return ELIMIT;
00486
00487 return block_read_direct(indev_handle, gba, cnt, buf);
00488 }
00489
00491 static int mbr_bd_write(part_t *p, uint64_t ba, size_t cnt, const void *buf)
00492 {
00493 uint64_t gba;
00494
00495 if (mbr_bsa_translate(p, ba, cnt, &gba) != EOK)
00496 return ELIMIT;
00497
00498 return block_write_direct(indev_handle, gba, cnt, buf);
00499 }
00500
00502 static int mbr_bsa_translate(part_t *p, uint64_t ba, size_t cnt, uint64_t *gba)
00503 {
00504 if (ba + cnt > p->length)
00505 return ELIMIT;
00506
00507 *gba = p->start_addr + ba;
00508 return EOK;
00509 }
00510