123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- #define pr_fmt(fmt) "blkpart: " fmt
- #include <stdio.h>
- #include <stdint.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include <blkpart.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #define MIN(a, b) ((a) > (b) ? (b) : (a))
- #define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a))
- #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
- #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
- static struct blkpart *blk_head = NULL;
- void blkpart_del_list(struct blkpart *blk)
- {
- struct blkpart *pblk, *pre;
- if (!blk_head)
- {
- return;
- }
- pblk = pre = blk_head;
- for (pblk = blk_head; pblk; pre = pblk, pblk = pblk->next)
- {
- if (pblk == blk)
- {
- if (pblk == blk_head)
- {
- blk_head = NULL;
- }
- else
- {
- pre->next = pblk->next;
- }
- break;
- }
- }
- }
- void blkpart_add_list(struct blkpart *blk)
- {
- struct blkpart *pblk, *pre;
- blk->next = NULL;
- if (!blk_head)
- {
- blk_head = blk;
- return;
- }
- pblk = pre = blk_head;
- while (pblk)
- {
- pre = pblk;
- pblk = pblk->next;
- }
- pre->next = blk;
- }
- void del_blkpart(struct blkpart *blk)
- {
- int i;
- if (!blk)
- {
- return;
- }
- for (i = 0; i < blk->n_parts; i++)
- {
- struct part *part = &blk->parts[i];
- if (!part)
- {
- continue;
- }
- }
- blkpart_del_list(blk);
- }
- struct part *get_part_by_index(const char *blk_name, uint32_t index)
- {
- struct blkpart *blk = blk_head;
- for (blk = blk_head; blk; blk = blk->next)
- {
- if (!strcmp(blk_name, blk->name))
- {
- if (index == 0)
- {
- return &blk->root;
- }
- else if (index == PARTINDEX_THE_LAST)
- {
- return &blk->parts[blk->n_parts - 1];
- }
- else if (blk->n_parts >= index)
- {
- return &blk->parts[index - 1];
- }
- else
- {
- return NULL;
- }
- }
- }
- return NULL;
- }
- #ifdef CONFIG_BLKPART_SHOW_INFO_CMD
- static int part_info_main(int argc, char **argv)
- {
- int i;
- struct blkpart *blk;
- struct part *part;
- for (blk = blk_head; blk; blk = blk->next)
- {
- for (i = 0; i < blk->n_parts; i++)
- {
- part = &blk->parts[i];
- printf("%s(%s): bytes 0x%llx off 0x%llx\n", part->name, part->devname,
- part->bytes, part->off);
- }
- }
- return 0;
- }
- FINSH_FUNCTION_EXPORT_CMD(part_info_main, __cmd_part_info, dump nor partitions);
- #endif
- struct part *get_part_by_name(const char *name)
- {
- struct blkpart *blk;
- if (!strncmp(name, "/dev/", sizeof("/dev/") - 1))
- {
- name += sizeof("/dev/") - 1;
- }
- for (blk = blk_head; blk; blk = blk->next)
- {
- int i;
- for (i = 0; i < blk->n_parts; i++)
- {
- struct part *part = &blk->parts[i];
- if (!strcmp(part->name, name))
- {
- return part;
- }
- if (!strcmp(part->devname, name))
- {
- return part;
- }
- }
- }
- return NULL;
- }
- struct blkpart *get_blkpart_by_name(const char *name)
- {
- struct blkpart *blk;
- if (!name)
- {
- return blk_head;
- }
- for (blk = blk_head; blk; blk = blk->next)
- {
- if (!strcmp(blk->name, name))
- {
- return blk;
- }
- }
- return NULL;
- }
- rt_size_t part_read(rt_device_t dev, rt_off_t offset, void *data, rt_size_t size)
- {
- if (size == 0)
- {
- return 0;
- }
- ssize_t ret, sz = 0;
- struct part *part = (struct part *)dev->user_data;
- struct blkpart *blk = part->blk;
- rt_device_t spinor_dev = blk->dev;
- size *= blk->blk_bytes; /* sector to size */
- offset *= blk->blk_bytes;
- char *page_buf = NULL;
- if (offset >= part->bytes)
- {
- printf("read offset %lu over part size %lu\n", offset, part->bytes);
- return 0;
- }
- if (offset + size > part->bytes)
- {
- printf("read %s(%s) over limit: offset %lu + size %lu over %lu\n",
- part->name, part->devname, offset, size, part->bytes);
- }
- size = MIN(part->bytes - offset, size);
- pr_debug("read %s(%s) off 0x%x size %lu\n", part->name, part->devname,
- offset, size);
- offset += part->off;
- if (offset % blk->page_bytes || size % blk->page_bytes)
- {
- page_buf = malloc(blk->page_bytes);
- if (!page_buf)
- {
- return -ENOMEM;
- }
- memset(page_buf, 0, blk->page_bytes);
- }
- /**
- * Step 1:
- * read the beginning data that not align to block size
- */
- if (offset % blk->page_bytes)
- {
- uint32_t addr, poff, len;
- addr = ALIGN_DOWN(offset, blk->page_bytes);
- poff = offset - addr;
- len = MIN(blk->page_bytes - poff, size);
- pr_debug("offset %lu not align %u, fix them before align read\n",
- offset, blk->blk_bytes);
- pr_debug("step1: read page data from addr 0x%x\n", addr);
- ret = spinor_dev->read(spinor_dev, addr / blk->page_bytes, page_buf, blk->page_bytes / blk->page_bytes);
- ret *= blk->page_bytes;
- if (ret != blk->blk_bytes)
- {
- goto err;
- }
- pr_debug("step2: copy page data to buf with page offset 0x%x and len %u\n",
- poff, len);
- memcpy(data, page_buf + poff, len);
- offset += len;
- data += len;
- sz += len;
- size -= len;
- }
- /**
- * Step 2:
- * read data that align to block size
- */
- while (size >= blk->page_bytes)
- {
- uint32_t len = (size/blk->page_bytes)*blk->page_bytes;
- ret = spinor_dev->read(spinor_dev, offset / blk->blk_bytes, (char *)data, len / blk->blk_bytes);
- ret *= blk->page_bytes;
- if (ret != len)
- {
- goto err;
- }
- offset += len;
- data += len;
- sz += len;
- size -= len;
- }
- /**
- * Step 3:
- * read the last data that not align to block size
- */
- if (size)
- {
- pr_debug("last size %u not align %u, read them\n", size, blk->blk_bytes);
- pr_debug("step1: read page data from addr 0x%x\n", offset);
- ret = spinor_dev->read(spinor_dev, offset / blk->blk_bytes, page_buf, blk->page_bytes / blk->page_bytes);
- ret *= blk->page_bytes;
- if (ret != blk->page_bytes)
- {
- goto err;
- }
- pr_debug("step2: copy page data to buf with page with len %u\n", size);
- memcpy(data, page_buf, size);
- sz += size;
- }
- #ifdef DEBUG
- pr_debug("read data:\n");
- hexdump(data, sz);
- #endif
- ret = 0;
- goto out;
- err:
- pr_err("read failed - %d\n", (int)ret);
- out:
- if (page_buf)
- {
- free(page_buf);
- }
- return ret ? ret / blk->blk_bytes: sz / blk->blk_bytes;
- }
- int do_write_without_erase(rt_device_t dev, struct blkpart *blk, uint32_t addr, uint32_t size, char *buf)
- {
- return dev->write(dev, addr, buf, size);
- }
- static int do_erase_write_blk(rt_device_t dev, struct blkpart *blk, uint32_t addr, uint32_t size, char *buf)
- {
- #if 0
- /* The code is prepared for elmfat which mounted at spinor */
- int ret;
- uint8_t *read_buf;
- unsigned int align_addr = ALIGN_DOWN(addr, blk->blk_bytes);
- read_buf = malloc(blk->blk_bytes);
- if (!read_buf)
- {
- return -ENOMEM;
- }
- memset(read_buf, 0, blk->blk_bytes);
- ret = dev->read(dev, align_addr, read_buf, blk->blk_bytes);
- if (ret != blk->blk_bytes)
- {
- free(read_buf);
- return -EIO;
- }
- if (!(align_addr % blk->blk_bytes))
- {
- blk_dev_erase_t erase_sector;
- memset(&erase_sector, 0, sizeof(blk_dev_erase_t));
- erase_sector.addr = align_addr;
- erase_sector.len = blk->blk_bytes;
- ret = dev->control(dev, BLOCK_DEVICE_CMD_ERASE_SECTOR, &erase_sector);
- if (ret)
- {
- free(read_buf);
- return ret;
- }
- }
- memcpy(read_buf + (addr - align_addr), buf, blk->page_bytes);
- ret = dev->write(dev, align_addr, read_buf, blk->blk_bytes);
- free(read_buf);
- if (ret == blk->blk_bytes)
- {
- return blk->page_bytes;
- }
- else
- {
- return -EIO;
- }
- #else
- int ret = -1;
- blk_dev_erase_t erase_sector;
- memset(&erase_sector, 0, sizeof(blk_dev_erase_t));
- erase_sector.addr = addr;
- erase_sector.len = size;
- ret = dev->control(dev, BLOCK_DEVICE_CMD_ERASE_SECTOR, &erase_sector);
- if (ret)
- {
- return -EIO;
- }
- ret = dev->write(dev, addr, buf, size);
- if (ret == size)
- {
- return size;
- }
- else
- {
- return -EIO;
- }
- #endif
- }
- rt_size_t _part_write(rt_device_t dev, rt_off_t offset, const void *data, rt_size_t size, int erase_before_write)
- {
- ssize_t ret, sz = 0;
- struct part *part = (struct part *)dev->user_data;
- struct blkpart *blk = part->blk;
- rt_device_t spinor_dev = blk->dev;
- char *blk_buf = NULL;
- int (*pwrite)(rt_device_t dev, struct blkpart * blk, uint32_t addr, uint32_t size, char *buf);
- if (size == 0)
- {
- return 0;
- }
- size *= blk->blk_bytes; /* sector to size */
- offset *= blk->blk_bytes;
- if (offset >= part->bytes)
- {
- printf("write offset %lu over part size %lu\n", offset, part->bytes);
- return 0;
- }
- if (offset + size > part->bytes)
- {
- printf("write %s(%s) over limit: offset %lu + size %lu over %lu\n",
- part->name, part->devname, offset, size, part->bytes);
- }
- size = MIN(part->bytes - offset, size);
- pr_debug("write %s(%s) off 0x%x size %lu (erase %d)\n", part->name,
- part->devname, offset, size, erase_before_write);
- offset += part->off;
- if (offset % blk->blk_bytes || size % blk->blk_bytes)
- {
- blk_buf = malloc(blk->blk_bytes);
- if (!blk_buf)
- {
- return -ENOMEM;
- }
- memset(blk_buf, 0, blk->blk_bytes);
- }
- if (erase_before_write)
- {
- pwrite = do_erase_write_blk;
- }
- else
- {
- pwrite = do_write_without_erase;
- }
- /**
- * Step 1:
- * write the beginning data that not align to block size
- */
- if (offset % blk->blk_bytes)
- {
- uint32_t addr, poff, len;
- addr = ALIGN_DOWN(offset, blk->blk_bytes);
- poff = offset - addr;
- len = MIN(blk->blk_bytes - poff, size);
- pr_debug("offset %u not align %u, fix them before align write\n",
- offset, blk->blk_bytes);
- pr_debug("step1: read page data from addr 0x%x\n", addr);
- ret = spinor_dev->read(spinor_dev, addr / blk->blk_bytes, blk_buf, blk->blk_bytes / blk->blk_bytes);
- ret *= blk->blk_bytes;
- if (ret != blk->blk_bytes)
- {
- goto err;
- }
- /* addr must less or equal to address */
- pr_debug("step2: copy buf data to page data with page offset 0x%x and len %u\n",
- poff, len);
- memcpy(blk_buf + poff, data, len);
- pr_debug("step3: flush the fixed page data\n");
- ret = pwrite(spinor_dev, blk, addr / blk->blk_bytes, blk->blk_bytes / blk->blk_bytes, blk_buf);
- ret *= blk->blk_bytes;
- if (ret != blk->blk_bytes)
- {
- goto err;
- }
- offset += len;
- data += len;
- sz += len;
- size -= len;
- }
- while (size >= blk->blk_bytes)
- {
- uint32_t len = (size/blk->blk_bytes)*blk->blk_bytes;
- ret = pwrite(spinor_dev, blk, offset / blk->blk_bytes, len / blk->blk_bytes, (char *)data);
- ret *= blk->blk_bytes;
- if (ret != len)
- {
- goto err;
- }
- offset += len;
- data += len;
- sz += len;
- size -= len;
- }
- if (size)
- {
- pr_debug("last size %u not align %u, write them\n", size, blk->blk_bytes);
- pr_debug("step1: read page data from addr 0x%x\n", offset);
- memset(blk_buf, 0x00, sizeof(blk->blk_bytes));
- ret = spinor_dev->read(spinor_dev, offset / blk->blk_bytes, blk_buf, blk->blk_bytes);
- if (ret != blk->blk_bytes)
- {
- goto err;
- }
- pr_debug("step2: copy buf to page data with page with len %u\n", size);
- memcpy(blk_buf, data, size);
- pr_debug("step3: flush the fixed page data\n");
- ret = pwrite(spinor_dev, blk, offset / blk->blk_bytes, blk->blk_bytes / blk->blk_bytes, blk_buf);
- ret *= blk->blk_bytes;
- if (ret != blk->blk_bytes)
- {
- goto err;
- }
- sz += size;
- }
- #ifdef DEBUG
- pr_debug("write data:\n");
- hexdump(data, sz);
- #endif
- ret = 0;
- goto out;
- err:
- pr_err("write failed - %d\n", (int)ret);
- out:
- if (blk_buf)
- {
- free(blk_buf);
- }
- return ret ? ret / blk->blk_bytes: sz / blk->blk_bytes;
- }
- rt_size_t part_erase_before_write(rt_device_t dev, rt_off_t offset, const void *data, rt_size_t size)
- {
- return _part_write(dev, offset, data, size, 1);
- }
- rt_size_t part_erase_without_write(rt_device_t dev, rt_off_t offset, const void *data, rt_size_t size)
- {
- return _part_write(dev, offset, data, size, 0);
- }
- rt_err_t part_control(rt_device_t dev, int cmd, void *args)
- {
- rt_err_t ret = -1;
- struct part *part = (struct part *)dev->user_data;
- struct blkpart *blk = part->blk;
- rt_device_t spinor_dev = blk->dev;
- struct rt_device_blk_geometry *geometry = NULL;
- blk_dev_erase_t *erase_sector = (blk_dev_erase_t *)args;
- switch (cmd)
- {
- case DEVICE_PART_CMD_ERASE_SECTOR:
- erase_sector = (blk_dev_erase_t *)(args);
- if (erase_sector->addr + erase_sector->len > part->bytes)
- {
- printf("erase %s(%s) over limit: offset %u + size %u over %lu\n",
- part->name, part->devname, erase_sector->addr, erase_sector->len, part->bytes);
- }
- erase_sector->len = MIN(part->bytes - erase_sector->addr, erase_sector->len);
- erase_sector->addr = erase_sector->addr + part->off;
- if (spinor_dev && spinor_dev->control)
- {
- ret = spinor_dev->control(spinor_dev, BLOCK_DEVICE_CMD_ERASE_SECTOR, erase_sector);
- }
- break;
- case DEVICE_PART_CMD_GET_BLOCK_SIZE:
- if (spinor_dev && spinor_dev->control)
- {
- ret = spinor_dev->control(spinor_dev, BLOCK_DEVICE_CMD_GET_BLOCK_SIZE, args);
- }
- else
- {
- ret = -1;
- }
- break;
- case DEVICE_PART_CMD_GET_TOTAL_SIZE:
- *(unsigned int *)args = part->bytes;
- ret = 0;
- break;
- case RT_DEVICE_CTRL_BLK_GETGEOME:
- geometry = (struct rt_device_blk_geometry *)args;
- memset(geometry, 0, sizeof(struct rt_device_blk_geometry));
- if (spinor_dev && spinor_dev->control)
- {
- ret = spinor_dev->control(spinor_dev, RT_DEVICE_CTRL_BLK_GETGEOME, args);
- if (!ret)
- {
- geometry->sector_count = part->bytes / geometry->bytes_per_sector;
- ret = 0;
- }
- }
- break;
- case RT_DEVICE_CTRL_BLK_ERASE:
- ret = 0;
- break;
- default:
- break;
- }
- return ret;
- }
|