Changeset 8f6c7785 in mainline for uspace/lib/mbr/libmbr.c


Ignore:
Timestamp:
2013-04-26T02:55:32Z (11 years ago)
Author:
Dominik Taborsky (AT DOT) <brembyseznamcz>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
700f89e
Parents:
d617050
Message:

logical write functional

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/mbr/libmbr.c

    rd617050 r8f6c7785  
    3333 */
    3434
     35#include <async.h>
     36#include <assert.h>
     37#include <block.h>
     38#include <byteorder.h>
     39#include <errno.h>
    3540#include <ipc/bd.h>
    36 #include <async.h>
     41#include <mem.h>
    3742#include <stdio.h>
    38 #include <block.h>
    39 #include <errno.h>
    4043#include <stdlib.h>
    41 #include <assert.h>
    42 #include <byteorder.h>
    4344
    4445#include "libmbr.h"
     
    4748static int decode_part(pt_entry_t * src, mbr_part_t * trgt, uint32_t base);
    4849static int decode_logical(mbr_t * mbr, mbr_partitions_t * p, mbr_part_t * ext);
    49 static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base);
     50static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr);
    5051static int check_overlap(mbr_part_t * p1, mbr_part_t * p2);
    5152static int check_encaps(mbr_part_t * inner, mbr_part_t * outer);
    5253static int check_preceeds(mbr_part_t * preceeder, mbr_part_t * precedee);
     54
     55static void debug_print(unsigned char * data, size_t bytes);
    5356
    5457/** Read MBR from specific device
     
    128131mbr_partitions_t * mbr_read_partitions(mbr_t * mbr)
    129132{
    130         int rc, i;
     133        int rc, i, rc_ext;
    131134        mbr_part_t * p;
    132135        mbr_part_t * ext = NULL;
    133136        mbr_partitions_t * parts;
    134 
     137       
    135138        if (mbr == NULL)
    136139                return NULL;
    137 
     140       
    138141        parts = mbr_alloc_partitions();
    139142        if (parts == NULL) {
     
    145148                if (mbr->raw_data.pte[i].ptype == PT_UNUSED)
    146149                        continue;
    147 
    148                 p = malloc(sizeof(mbr_part_t));
     150               
     151                //p = malloc(sizeof(mbr_part_t));
     152                p = mbr_alloc_partition();
    149153                if (p == NULL) {
    150154                        printf(LIBMBR_NAME ": Error on memory allocation.\n");
    151                         free(p);
    152155                        mbr_free_partitions(parts);
    153156                        return NULL;
    154157                }
    155158                //list_append(&(p->link), &(parts->list));
    156                 p->ebr = NULL;
    157                 if (decode_part(&(mbr->raw_data.pte[i]), p, 0)) {
     159                rc_ext = decode_part(&(mbr->raw_data.pte[i]), p, 0);
     160                mbr_set_flag(p, ST_LOGIC, false);
     161                rc = mbr_add_partition(parts, p);
     162                if (rc != ERR_OK) {
     163                        printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
     164                                   LIBMBR_NAME ": Partition list may be incomplete.\n", rc);
     165                        return NULL;
     166                }
     167               
     168                if (rc_ext) {
    158169                        ext = p;
    159170                        parts->l_extended = list_last(&(parts->list));
    160171                }
    161                 mbr_set_flag(p, ST_LOGIC, false);
    162                 mbr_add_partition(parts, p);
    163         }
    164 
     172        }
     173       
    165174        // Fill in the primary partitions and generate logical ones, if any
    166175        rc = decode_logical(mbr, parts, ext);
     
    169178                           LIBMBR_NAME ": Partition list may be incomplete.\n");
    170179        }
    171 
     180       
     181        //DEBUG:
     182        //debug_print((unsigned char *) list_get_instance(list_last(&(parts->list)), mbr_part_t, link)->ebr, 512);
    172183        return parts;
    173184}
     
    188199        mbr_part_t * ext = (parts->l_extended == NULL) ? NULL
    189200                                        : list_get_instance(parts->l_extended, mbr_part_t, link);
    190 
     201       
    191202        //br_block_t * last_ebr = NULL;
    192203        //link_t * it;
    193 
     204       
    194205        DEBUG_PRINT_3(LIBMBR_NAME "Writing partitions: n_primary: %u, n_logical:%u, l_extended:%p", parts->n_primary, parts->n_logical, parts->l_extended);
    195 
     206       
    196207        rc = block_init(EXCHANGE_ATOMIC, dev_handle, 512);
    197208        if (rc != EOK) {
     
    228239
    229240        }*/
    230 
     241       
    231242        link_t * l = parts->list.head.next;
    232 
     243       
    233244        // Encoding primary partitions
    234245        for (i = 0; i < parts->n_primary; i++) {
    235246                p = list_get_instance(l, mbr_part_t, link);
    236                 encode_part(p, &(mbr->raw_data.pte[i]), 0);
     247                encode_part(p, &(mbr->raw_data.pte[i]), 0, false);
    237248                l = l->next;
    238249        }
    239 
     250       
    240251        // Writing MBR
    241252        rc = block_write_direct(dev_handle, 0, 1, &(mbr->raw_data));
     
    244255                goto end;
    245256        }
    246 
     257       
    247258        if (ext == NULL)
    248259                goto no_extended;
    249 
    250 
     260       
     261        //DEBUG:
     262        //debug_print((unsigned char *) list_get_instance(list_last(&(parts->list)), mbr_part_t, link)->ebr, 512);
    251263        uint32_t base = ext->start_addr;
    252         uint32_t addr = base;
    253 
     264        //uint32_t addr = base;
     265        //uint32_t prev_addr;
     266        //mbr_part_t * tmp;
     267        mbr_part_t * prev_p;
    254268        // Encoding and writing first logical partition
    255269        if (l != &(parts->list.head)) {
    256270                p = list_get_instance(l, mbr_part_t, link);
    257                 if (p->ebr == NULL) {
    258                         p->ebr = alloc_br();
    259                         if (p->ebr == NULL) {
    260                                 rc = ENOMEM;
    261                                 goto end;
    262                         }
    263                 }
    264 
    265                 encode_part(p, &(p->ebr->pte[0]), base);
    266 
    267                 if (l->next == &(parts->list.head))
    268                         encode_part(NULL, &(p->ebr->pte[1]), base);
    269                 else
    270                         encode_part(list_get_instance(l->next, mbr_part_t, link), &(p->ebr->pte[1]), base);
    271 
    272 
     271                p->ebr_addr = base;
     272                encode_part(p, &(p->ebr->pte[0]), base, false);
     273               
     274                /*if (l->next == &(parts->list.head))
     275                        encode_part(NULL, &(p->ebr->pte[1]), base, false);
     276                else {
     277                        tmp = list_get_instance(l->next, mbr_part_t, link);
     278                        //debug_print((unsigned char*) p->ebr, 512);
     279                        printf("DEBUG: base: %u, tmp: start: %u, end: %u\n", base, tmp->start_addr, tmp->start_addr + tmp->length);
     280                        //encode_part(tmp, &(p->ebr->pte[1]), base);
     281                        encode_part(tmp, &(p->ebr->pte[1]), base, true);
     282                        debug_print(((unsigned char*) p->ebr) + 446, 32);
     283                }
     284               
    273285                rc = block_write_direct(dev_handle, base, 1, p->ebr);
    274286                if (rc != EOK) {
    275287                        DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
    276288                        goto end;
    277                 }
    278 
     289                }*/
     290               
    279291                l = l->next;
    280         }
    281 
    282 
    283 
     292        } else
     293                goto no_logical;
     294       
     295        //prev_addr = base;
     296        prev_p = p;
     297       
    284298        // Encoding and writing logical partitions
    285299        while (l != &(parts->list.head)) {
    286300                p = list_get_instance(l, mbr_part_t, link);
    287                 if (p->ebr == NULL) {
    288                         p->ebr = alloc_br();
    289                         if (p->ebr == NULL) {
    290                                 rc = ENOMEM;
    291                                 goto end;
    292                         }
    293                 }
    294 
    295                 addr = p->start_addr - base;
    296                 encode_part(p, &(p->ebr->pte[0]), addr);
    297 
    298                 if (l->next == &(parts->list.head))
    299                         encode_part(NULL, &(p->ebr->pte[1]), base);
     301               
     302                /* Checking whether EBR address makes sense. If not, we take a guess.
     303                 * So far this is simple, we just take the first preceeding sector.
     304                 * Fdisk always reserves at least 2048 sectors (1MiB), so it can have
     305                 * the EBR aligned as well as the partition itself. Parted reserves
     306                 * minimum one sector, like we do.
     307                 *
     308                 * Note that we know there is at least one sector free from previous checks.
     309                 * Also note that the user can set ebr_addr to their liking (if it's valid). */         
     310                if (p->ebr_addr >= p->start_addr || p->ebr_addr <= (prev_p->start_addr + prev_p->length)) {
     311                        p->ebr_addr = p->start_addr - 1;
     312                        DEBUG_PRINT_0(LIBMBR_NAME ": Warning: invalid EBR address.\n");
     313                }
     314               
     315                encode_part(p, &(p->ebr->pte[0]), p->ebr_addr, false);
     316                debug_print(((unsigned char*) p->ebr) + 446, 32);
     317                encode_part(p, &(prev_p->ebr->pte[1]), base, true);
     318                debug_print(((unsigned char*) prev_p->ebr) + 446, 32);
     319                /*if (l->next == &(parts->list.head))
     320                        encode_part(NULL, &(p->ebr->pte[1]), base, false);
    300321                else
    301                         encode_part(list_get_instance(l->next, mbr_part_t, link), &(p->ebr->pte[1]), base);
    302 
    303 
    304                 rc = block_write_direct(dev_handle, addr, 1, p->ebr);
     322                        encode_part(list_get_instance(l->next, mbr_part_t, link), &(p->ebr->pte[1]), base, true);
     323                */
     324               
     325                rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
    305326                if (rc != EOK) {
    306327                        DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
    307328                        goto end;
    308329                }
    309 
     330               
     331                prev_p = p;
    310332                l = l->next;
    311333        }
    312 
     334       
     335        encode_part(NULL, &(prev_p->ebr->pte[1]), 0, false);
     336        rc = block_write_direct(dev_handle, prev_p->ebr_addr, 1, prev_p->ebr);
     337        if (rc != EOK) {
     338                DEBUG_PRINT_2(LIBMBR_NAME ": Error (%d): %s.\n", rc, str_error(rc));
     339                goto end;
     340        }
     341       
     342no_logical:
    313343no_extended:
    314 
     344       
    315345        /*if (ext == NULL)
    316346                goto no_extended;
     
    514544                p = p->next;
    515545        }*/
    516 
     546       
    517547        rc = EOK;
    518 
     548       
    519549end:
    520550        block_fini(dev_handle);
    521 
     551       
    522552        return rc;
    523553}
     
    536566        p->start_addr = 0;
    537567        p->length = 0;
     568        p->ebr_addr = 0;
    538569
    539570        return p;
     
    561592int mbr_add_partition(mbr_partitions_t * parts, mbr_part_t * p)
    562593{
    563         if (mbr_get_flag(p, ST_LOGIC)) {
    564                 // adding logical part
     594        if (mbr_get_flag(p, ST_LOGIC)) { // adding logical part
    565595                if (parts->l_extended == NULL) {
    566596                        return ERR_NO_EXTENDED;
    567597                }
    568                 if (!check_encaps(p, list_get_instance(parts->l_extended, mbr_part_t, link))) {
     598                mbr_part_t * ext = list_get_instance(parts->l_extended, mbr_part_t, link);
     599                if (!check_encaps(p, ext)) {
     600                        //printf("DEBUG: OOB: start: %u, end: %u\n", h->start_addr, h->start_addr + h->length);
     601                        //printf("DEBUG: OOB: start: %u, end: %u\n", p->start_addr, p->start_addr + p->length);
    569602                        return ERR_OUT_BOUNDS;
    570603                }
    571604
    572605                mbr_part_t * last = list_get_instance(list_last(&(parts->list)), mbr_part_t, link);
     606                mbr_part_t * iter;
     607                uint32_t ebr_space = 1;
    573608                mbr_part_foreach(parts, iter) {
    574609                        if (mbr_get_flag(iter, ST_LOGIC)) {
    575610                                if (check_overlap(p, iter)) {
     611                                        //printf("DEBUG: overlap: start: %u, end: %u\n", iter->start_addr, iter->start_addr + iter->length);
     612                                        //printf("DEBUG: overlap: start: %u, end: %u\n", p->start_addr, p->start_addr + p->length);
    576613                                        return ERR_OVERLAP;
    577614                                }
    578                                 if (check_preceeds(p, iter)) {
     615                                if (check_preceeds(iter, p)) {
    579616                                        last = iter;
     617                                        ebr_space = p->start_addr - (last->start_addr + last->length);
     618                                } else
    580619                                        break;
    581                                 }
    582620                        }
    583621                }
    584 
     622               
     623                // checking if there's at least one sector of space preceeding
     624               
     625                if (ebr_space < 1)
     626                        return ERR_NO_EBR;
     627               
     628                // checking if there's at least one sector of space following (for following partitions's EBR)
     629                if (last->link.next != &(parts->list.head)) {
     630                        if (list_get_instance(&(last->link.next), mbr_part_t, link)->start_addr <= p->start_addr + p->length + 1) {
     631                                return ERR_NO_EBR;
     632                        }
     633                }
     634               
     635                if (p->ebr == NULL) {
     636                        p->ebr = alloc_br();
     637                        if (p->ebr == NULL) {
     638                                return ERR_NOMEM;
     639                        }
     640                }
     641               
     642                //printf("DEBUG: last: start: %u\n", last->start_addr);
    585643                //list_prepend(&(p->link), &(parts->list));
    586                 list_insert_before(&(p->link), &(last->link));
     644                list_insert_after(&(p->link), &(last->link));
    587645                parts->n_logical += 1;
    588646        } else {
     
    591649                        return ERR_PRIMARY_FULL;
    592650                }
     651               
     652                // should we check if it's inside the drive's upper boundary?
     653                if (p->start_addr == 0) {
     654                        return ERR_OUT_BOUNDS;
     655                }
     656               
    593657                if (p->type == PT_EXTENDED && parts->l_extended != NULL) {
    594658                        return ERR_EXTENDED_PRESENT;
     
    598662                        list_append(&(p->link), &(parts->list));
    599663                } else {
     664                        mbr_part_t * iter;
    600665                        mbr_part_foreach(parts, iter) {
    601666                                if (mbr_get_flag(iter, ST_LOGIC)) {
    602667                                        list_insert_before(&(p->link), &(iter->link));
    603                                         parts->n_primary += 1;
    604668                                        break;
    605669                                } else if (check_overlap(p, iter)) {
     
    607671                                }
    608672                        }
    609                 }
     673                        if (iter == list_get_instance(&(parts->list.head.prev), mbr_part_t, link)) {
     674                                list_append(&(p->link), &(parts->list));
     675                        }
     676                       
     677                }
     678                parts->n_primary += 1;
    610679        }
    611680
     
    663732}
    664733
     734/** Get next aligned address (in sectors!) */
     735uint32_t mbr_get_next_aligned(uint32_t addr, unsigned int alignment)
     736{
     737        uint32_t div = addr / alignment;
     738        return (div + 1) * alignment;
     739}
     740
    665741/** Just a wrapper for free() */
    666742void mbr_free_mbr(mbr_t * mbr)
     
    691767        if (br == NULL)
    692768                return NULL;
    693 
     769       
     770        memset(br, 0, 512);
    694771        br->media_id = 0;
    695772        br->pad0 = 0;
    696773        br->signature = host2uint16_t_le(BR_SIGNATURE);
    697 
     774       
    698775        return br;
    699776}
     
    733810        uint32_t addr = base;
    734811        br_block_t * ebr;
    735 
     812       
    736813        rc = block_init(EXCHANGE_ATOMIC, mbr->device, 512);
    737814        if (rc != EOK)
    738815                return rc;
    739 
     816       
    740817        ebr = alloc_br();
    741818        if (ebr == NULL) {
     
    743820                goto end;
    744821        }
    745 
     822       
    746823        rc = block_read_direct(mbr->device, addr, 1, ebr);
    747824        if (rc != EOK) {
    748825                goto free_ebr_end;
    749826        }
    750 
     827       
    751828        if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
    752829                rc = EINVAL;
    753830                goto free_ebr_end;
    754831        }
    755 
     832       
    756833        if (ebr->pte[0].ptype == PT_UNUSED) {
    757834                rc = EOK;
    758835                goto free_ebr_end;
    759836        }
    760 
     837       
    761838        p = mbr_alloc_partition();
    762839        if (p == NULL) {
     
    764841                goto free_ebr_end;
    765842        }
    766 
    767 
     843       
    768844        decode_part(&(ebr->pte[0]), p, base);
    769845        mbr_set_flag(p, ST_LOGIC, true);
    770846        p->ebr = ebr;
    771         mbr_add_partition(parts, p);
    772 
     847        p->ebr_addr = addr;
     848        rc = mbr_add_partition(parts, p);
     849        if (rc != ERR_OK) {
     850                printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
     851                           LIBMBR_NAME ": Partition list may be incomplete.\n", rc);
     852                return EINVAL;
     853        }
     854       
    773855        addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
    774 
     856        printf("DEBUG: b: %u, a: %u, start: %u\n", base, addr, ebr->pte[1].first_lba);
     857       
    775858        while (ebr->pte[1].ptype != PT_UNUSED) {
    776859                ebr = alloc_br();
     
    779862                        goto end;
    780863                }
    781 
     864               
    782865                rc = block_read_direct(mbr->device, addr, 1, ebr);
    783866                if (rc != EOK) {
    784867                        goto free_ebr_end;
    785868                }
    786 
     869               
    787870                if (uint16_t_le2host(ebr->signature) != BR_SIGNATURE) {
    788871                        rc = EINVAL;
    789872                        goto free_ebr_end;
    790873                }
    791 
     874               
    792875                p = mbr_alloc_partition();
    793876                if (p == NULL) {
     
    795878                        goto free_ebr_end;
    796879                }
    797 
    798                 decode_part(&(ebr->pte[0]), p, base);
     880               
     881                //printf("DEBUG: b: %u, a: %u, start: %u\n", base, addr, ebr->pte[0].first_lba);
     882                decode_part(&(ebr->pte[0]), p, addr);
    799883                mbr_set_flag(p, ST_LOGIC, true);
    800884                p->ebr = ebr;
    801                 mbr_add_partition(parts, p);
    802 
     885                p->ebr_addr = addr;
     886                rc = mbr_add_partition(parts, p);
     887                if (rc != ERR_OK) {
     888                        printf(LIBMBR_NAME ": Error occured during decoding the MBR. (%d)\n" \
     889                                   LIBMBR_NAME ": Partition list may be incomplete.\n", rc);
     890                        return EINVAL;
     891                }
     892               
    803893                addr = uint32_t_le2host(ebr->pte[1].first_lba) + base;
    804894        }
    805 
     895       
    806896        rc = EOK;
    807 
     897        goto end;
     898       
    808899free_ebr_end:
    809900        free(ebr);
    810 
     901       
    811902end:
    812903        block_fini(mbr->device);
    813 
     904       
    814905        return rc;
    815906}
    816907
    817908/** Convert mbr_part_t to pt_entry_t */
    818 static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base)
     909static void encode_part(mbr_part_t * src, pt_entry_t * trgt, uint32_t base, bool ebr)
    819910{
    820911        if (src != NULL) {
    821912                trgt->status = mbr_get_flag(src, ST_BOOT) ? B_ACTIVE : B_INACTIVE;
    822                 trgt->ptype = src->type;
    823                 trgt->first_lba = host2uint32_t_le(src->start_addr - base);
    824                 trgt->length = host2uint32_t_le(src->length);
     913                if (ebr) {      // encoding reference to EBR
     914                        trgt->ptype = PT_EXTENDED_LBA;
     915                        trgt->first_lba = host2uint32_t_le(src->ebr_addr - base);
     916                        trgt->length = host2uint32_t_le(src->length + src->start_addr - src->ebr_addr);
     917                } else {        // encoding reference to partition
     918                        trgt->ptype = src->type;
     919                        trgt->first_lba = host2uint32_t_le(src->start_addr - base);
     920                        trgt->length = host2uint32_t_le(src->length);
     921                }
    825922        } else {
    826923                trgt->status = 0;
     
    839936static int check_overlap(mbr_part_t * p1, mbr_part_t * p2)
    840937{
    841         if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length <= p2->start_addr) {
     938        if (p1->start_addr < p2->start_addr && p1->start_addr + p1->length < p2->start_addr) {
    842939                return 0;
    843         } else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length <= p1->start_addr) {
     940        } else if (p1->start_addr > p2->start_addr && p2->start_addr + p2->length < p1->start_addr) {
    844941                return 0;
    845942        }
     
    864961}
    865962
    866 
    867 
     963static void debug_print(unsigned char * data, size_t bytes)
     964{
     965        size_t addr = 0;
     966        int i;
     967       
     968        while (bytes >= 16) {
     969                printf("%8x ", addr);
     970                for (i = 0; i < 8; i++) {
     971                        printf(" %2hhx", data[addr + i]);
     972                }
     973                printf(" ");
     974                for (i = 0; i < 8; i++) {
     975                        printf(" %2hhx", data[addr + i + 8]);
     976                }
     977                printf("\n");
     978               
     979                bytes -= 16;
     980                addr += 16;
     981        }
     982       
     983       
     984}
     985
     986
     987
Note: See TracChangeset for help on using the changeset viewer.