123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- /**
- * Copyright (c) 2011-2022 Bill Greiman
- * This file is part of the SdFat library for SD memory cards.
- *
- * MIT License
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- #define DBG_FILE "ExFatFormatter.cpp"
- #include "../common/DebugMacros.h"
- #include "../common/upcase.h"
- #include "ExFatLib.h"
- //------------------------------------------------------------------------------
- // Formatter assumes 512 byte sectors.
- const uint32_t BOOT_BACKUP_OFFSET = 12;
- const uint16_t BYTES_PER_SECTOR = 512;
- const uint16_t SECTOR_MASK = BYTES_PER_SECTOR - 1;
- const uint8_t BYTES_PER_SECTOR_SHIFT = 9;
- const uint16_t MINIMUM_UPCASE_SKIP = 512;
- const uint32_t BITMAP_CLUSTER = 2;
- const uint32_t UPCASE_CLUSTER = 3;
- const uint32_t ROOT_CLUSTER = 4;
- //------------------------------------------------------------------------------
- #define PRINT_FORMAT_PROGRESS 1
- #if !PRINT_FORMAT_PROGRESS
- #define writeMsg(pr, str)
- #elif defined(__AVR__)
- #define writeMsg(pr, str) if (pr) pr->print(F(str))
- #else // PRINT_FORMAT_PROGRESS
- #define writeMsg(pr, str) if (pr) pr->write(str)
- #endif // PRINT_FORMAT_PROGRESS
- //------------------------------------------------------------------------------
- bool ExFatFormatter::format(FsBlockDevice* dev, uint8_t* secBuf, print_t* pr) {
- #if !PRINT_FORMAT_PROGRESS
- (void)pr;
- #endif // !PRINT_FORMAT_PROGRESS
- MbrSector_t* mbr;
- ExFatPbs_t* pbs;
- DirUpcase_t* dup;
- DirBitmap_t* dbm;
- DirLabel_t* label;
- uint32_t bitmapSize;
- uint32_t checksum = 0;
- uint32_t clusterCount;
- uint32_t clusterHeapOffset;
- uint32_t fatLength;
- uint32_t fatOffset;
- uint32_t m;
- uint32_t ns;
- uint32_t partitionOffset;
- uint32_t sector;
- uint32_t sectorsPerCluster;
- uint32_t volumeLength;
- uint32_t sectorCount;
- uint8_t sectorsPerClusterShift;
- uint8_t vs;
- m_dev = dev;
- m_secBuf = secBuf;
- sectorCount = dev->sectorCount();
- // Min size is 512 MB
- if (sectorCount < 0X100000) {
- writeMsg(pr, "Device is too small\r\n");
- DBG_FAIL_MACRO;
- goto fail;
- }
- // Determine partition layout.
- for (m = 1, vs = 0; m && sectorCount > m; m <<= 1, vs++) {}
- sectorsPerClusterShift = vs < 29 ? 8 : (vs - 11)/2;
- sectorsPerCluster = 1UL << sectorsPerClusterShift;
- fatLength = 1UL << (vs < 27 ? 13 : (vs + 1)/2);
- fatOffset = fatLength;
- partitionOffset = 2*fatLength;
- clusterHeapOffset = 2*fatLength;
- clusterCount = (sectorCount - 4*fatLength) >> sectorsPerClusterShift;
- volumeLength = clusterHeapOffset + (clusterCount << sectorsPerClusterShift);
- // make Master Boot Record. Use fake CHS.
- memset(secBuf, 0, BYTES_PER_SECTOR);
- mbr = reinterpret_cast<MbrSector_t*>(secBuf);
- mbr->part->beginCHS[0] = 1;
- mbr->part->beginCHS[1] = 1;
- mbr->part->beginCHS[2] = 0;
- mbr->part->type = 7;
- mbr->part->endCHS[0] = 0XFE;
- mbr->part->endCHS[1] = 0XFF;
- mbr->part->endCHS[2] = 0XFF;
- setLe32(mbr->part->relativeSectors, partitionOffset);
- setLe32(mbr->part->totalSectors, volumeLength);
- setLe16(mbr->signature, MBR_SIGNATURE);
- if (!dev->writeSector(0, secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- // Partition Boot sector.
- memset(secBuf, 0, BYTES_PER_SECTOR);
- pbs = reinterpret_cast<ExFatPbs_t*>(secBuf);
- pbs->jmpInstruction[0] = 0XEB;
- pbs->jmpInstruction[1] = 0X76;
- pbs->jmpInstruction[2] = 0X90;
- pbs->oemName[0] = 'E';
- pbs->oemName[1] = 'X';
- pbs->oemName[2] = 'F';
- pbs->oemName[3] = 'A';
- pbs->oemName[4] = 'T';
- pbs->oemName[5] = ' ';
- pbs->oemName[6] = ' ';
- pbs->oemName[7] = ' ';
- setLe64(pbs->bpb.partitionOffset, partitionOffset);
- setLe64(pbs->bpb.volumeLength, volumeLength);
- setLe32(pbs->bpb.fatOffset, fatOffset);
- setLe32(pbs->bpb.fatLength, fatLength);
- setLe32(pbs->bpb.clusterHeapOffset, clusterHeapOffset);
- setLe32(pbs->bpb.clusterCount, clusterCount);
- setLe32(pbs->bpb.rootDirectoryCluster, ROOT_CLUSTER);
- setLe32(pbs->bpb.volumeSerialNumber, sectorCount);
- setLe16(pbs->bpb.fileSystemRevision, 0X100);
- setLe16(pbs->bpb.volumeFlags, 0);
- pbs->bpb.bytesPerSectorShift = BYTES_PER_SECTOR_SHIFT;
- pbs->bpb.sectorsPerClusterShift = sectorsPerClusterShift;
- pbs->bpb.numberOfFats = 1;
- pbs->bpb.driveSelect = 0X80;
- pbs->bpb.percentInUse = 0;
- // Fill boot code like official SDFormatter.
- for (size_t i = 0; i < sizeof(pbs->bootCode); i++) {
- pbs->bootCode[i] = 0XF4;
- }
- setLe16(pbs->signature, PBR_SIGNATURE);
- for (size_t i = 0; i < BYTES_PER_SECTOR; i++) {
- if (i == offsetof(ExFatPbs_t, bpb.volumeFlags[0]) ||
- i == offsetof(ExFatPbs_t, bpb.volumeFlags[1]) ||
- i == offsetof(ExFatPbs_t, bpb.percentInUse)) {
- continue;
- }
- checksum = exFatChecksum(checksum, secBuf[i]);
- }
- sector = partitionOffset;
- if (!dev->writeSector(sector, secBuf) ||
- !dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- sector++;
- // Write eight Extended Boot Sectors.
- memset(secBuf, 0, BYTES_PER_SECTOR);
- setLe16(pbs->signature, PBR_SIGNATURE);
- for (int j = 0; j < 8; j++) {
- for (size_t i = 0; i < BYTES_PER_SECTOR; i++) {
- checksum = exFatChecksum(checksum, secBuf[i]);
- }
- if (!dev->writeSector(sector, secBuf) ||
- !dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- sector++;
- }
- // Write OEM Parameter Sector and reserved sector.
- memset(secBuf, 0, BYTES_PER_SECTOR);
- for (int j = 0; j < 2; j++) {
- for (size_t i = 0; i < BYTES_PER_SECTOR; i++) {
- checksum = exFatChecksum(checksum, secBuf[i]);
- }
- if (!dev->writeSector(sector, secBuf) ||
- !dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- sector++;
- }
- // Write Boot CheckSum Sector.
- for (size_t i = 0; i < BYTES_PER_SECTOR; i += 4) {
- setLe32(secBuf + i, checksum);
- }
- if (!dev->writeSector(sector, secBuf) ||
- !dev->writeSector(sector + BOOT_BACKUP_OFFSET , secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- // Initialize FAT.
- writeMsg(pr, "Writing FAT ");
- sector = partitionOffset + fatOffset;
- ns = ((clusterCount + 2)*4 + BYTES_PER_SECTOR - 1)/BYTES_PER_SECTOR;
- memset(secBuf, 0, BYTES_PER_SECTOR);
- // Allocate two reserved clusters, bitmap, upcase, and root clusters.
- secBuf[0] = 0XF8;
- for (size_t i = 1; i < 20; i++) {
- secBuf[i] = 0XFF;
- }
- for (uint32_t i = 0; i < ns; i++) {
- if (i%(ns/32) == 0) {
- writeMsg(pr, ".");
- }
- if (!dev->writeSector(sector + i, secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- if (i == 0) {
- memset(secBuf, 0, BYTES_PER_SECTOR);
- }
- }
- writeMsg(pr, "\r\n");
- // Write cluster two, bitmap.
- sector = partitionOffset + clusterHeapOffset;
- bitmapSize = (clusterCount + 7)/8;
- ns = (bitmapSize + BYTES_PER_SECTOR - 1)/BYTES_PER_SECTOR;
- if (ns > sectorsPerCluster) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- memset(secBuf, 0, BYTES_PER_SECTOR);
- // Allocate clusters for bitmap, upcase, and root.
- secBuf[0] = 0X7;
- for (uint32_t i = 0; i < ns; i++) {
- if (!dev->writeSector(sector + i, secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- if (i == 0) {
- secBuf[0] = 0;
- }
- }
- // Write cluster three, upcase table.
- writeMsg(pr, "Writing upcase table\r\n");
- if (!writeUpcase(partitionOffset + clusterHeapOffset + sectorsPerCluster)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- if (m_upcaseSize > BYTES_PER_SECTOR*sectorsPerCluster) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- // Initialize first sector of root.
- writeMsg(pr, "Writing root\r\n");
- ns = sectorsPerCluster;
- sector = partitionOffset + clusterHeapOffset + 2*sectorsPerCluster;
- memset(secBuf, 0, BYTES_PER_SECTOR);
- // Unused Label entry.
- label = reinterpret_cast<DirLabel_t*>(secBuf);
- label->type = EXFAT_TYPE_LABEL & 0X7F;
- // bitmap directory entry.
- dbm = reinterpret_cast<DirBitmap_t*>(secBuf + 32);
- dbm->type = EXFAT_TYPE_BITMAP;
- setLe32(dbm->firstCluster, BITMAP_CLUSTER);
- setLe64(dbm->size, bitmapSize);
- // upcase directory entry.
- dup = reinterpret_cast<DirUpcase_t*>(secBuf + 64);
- dup->type = EXFAT_TYPE_UPCASE;
- setLe32(dup->checksum, m_upcaseChecksum);
- setLe32(dup->firstCluster, UPCASE_CLUSTER);
- setLe64(dup->size, m_upcaseSize);
- // Write root, cluster four.
- for (uint32_t i = 0; i < ns; i++) {
- if (!dev->writeSector(sector + i, secBuf)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- if (i == 0) {
- memset(secBuf, 0, BYTES_PER_SECTOR);
- }
- }
- writeMsg(pr, "Format done\r\n");
- return true;
- fail:
- writeMsg(pr, "Format failed\r\n");
- return false;
- }
- //------------------------------------------------------------------------------
- bool ExFatFormatter::syncUpcase() {
- uint16_t index = m_upcaseSize & SECTOR_MASK;
- if (!index) {
- return true;
- }
- for (size_t i = index; i < BYTES_PER_SECTOR; i++) {
- m_secBuf[i] = 0;
- }
- return m_dev->writeSector(m_upcaseSector, m_secBuf);
- }
- //------------------------------------------------------------------------------
- bool ExFatFormatter::writeUpcaseByte(uint8_t b) {
- uint16_t index = m_upcaseSize & SECTOR_MASK;
- m_secBuf[index] = b;
- m_upcaseChecksum = exFatChecksum(m_upcaseChecksum, b);
- m_upcaseSize++;
- if (index == SECTOR_MASK) {
- return m_dev->writeSector(m_upcaseSector++, m_secBuf);
- }
- return true;
- }
- //------------------------------------------------------------------------------
- bool ExFatFormatter::writeUpcaseUnicode(uint16_t unicode) {
- return writeUpcaseByte(unicode) && writeUpcaseByte(unicode >> 8);
- }
- //------------------------------------------------------------------------------
- bool ExFatFormatter::writeUpcase(uint32_t sector) {
- uint32_t n;
- uint32_t ns;
- uint32_t ch = 0;
- uint16_t uc;
- m_upcaseSize = 0;
- m_upcaseChecksum = 0;
- m_upcaseSector = sector;
- while (ch < 0X10000) {
- uc = toUpcase(ch);
- if (uc != ch) {
- if (!writeUpcaseUnicode(uc)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- ch++;
- } else {
- for (n = ch + 1; n < 0X10000 && n == toUpcase(n); n++) {}
- ns = n - ch;
- if (ns >= MINIMUM_UPCASE_SKIP) {
- if (!writeUpcaseUnicode(0XFFFF) || !writeUpcaseUnicode(ns)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- ch = n;
- } else {
- while (ch < n) {
- if (!writeUpcaseUnicode(ch++)) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- }
- }
- }
- }
- if (!syncUpcase()) {
- DBG_FAIL_MACRO;
- goto fail;
- }
- return true;
- fail:
- return false;
- }
|