Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Committer:
Pawel Zarembski
Date:
Tue Apr 07 12:55:42 2020 +0200
Revision:
0:01f31e923fe2
hani: DAPLink with reset workaround

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Pawel Zarembski 0:01f31e923fe2 1 /**
Pawel Zarembski 0:01f31e923fe2 2 * @file virtual_fs.c
Pawel Zarembski 0:01f31e923fe2 3 * @brief Implementation of virtual_fs.h
Pawel Zarembski 0:01f31e923fe2 4 *
Pawel Zarembski 0:01f31e923fe2 5 * DAPLink Interface Firmware
Pawel Zarembski 0:01f31e923fe2 6 * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
Pawel Zarembski 0:01f31e923fe2 7 * SPDX-License-Identifier: Apache-2.0
Pawel Zarembski 0:01f31e923fe2 8 *
Pawel Zarembski 0:01f31e923fe2 9 * Licensed under the Apache License, Version 2.0 (the "License"); you may
Pawel Zarembski 0:01f31e923fe2 10 * not use this file except in compliance with the License.
Pawel Zarembski 0:01f31e923fe2 11 * You may obtain a copy of the License at
Pawel Zarembski 0:01f31e923fe2 12 *
Pawel Zarembski 0:01f31e923fe2 13 * http://www.apache.org/licenses/LICENSE-2.0
Pawel Zarembski 0:01f31e923fe2 14 *
Pawel Zarembski 0:01f31e923fe2 15 * Unless required by applicable law or agreed to in writing, software
Pawel Zarembski 0:01f31e923fe2 16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
Pawel Zarembski 0:01f31e923fe2 17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Pawel Zarembski 0:01f31e923fe2 18 * See the License for the specific language governing permissions and
Pawel Zarembski 0:01f31e923fe2 19 * limitations under the License.
Pawel Zarembski 0:01f31e923fe2 20 */
Pawel Zarembski 0:01f31e923fe2 21
Pawel Zarembski 0:01f31e923fe2 22 #include <string.h>
Pawel Zarembski 0:01f31e923fe2 23
Pawel Zarembski 0:01f31e923fe2 24 #include "virtual_fs.h"
Pawel Zarembski 0:01f31e923fe2 25 #include "info.h"
Pawel Zarembski 0:01f31e923fe2 26 #include "settings.h"
Pawel Zarembski 0:01f31e923fe2 27 #include "compiler.h"
Pawel Zarembski 0:01f31e923fe2 28 #include "util.h"
Pawel Zarembski 0:01f31e923fe2 29
Pawel Zarembski 0:01f31e923fe2 30 // Virtual file system driver
Pawel Zarembski 0:01f31e923fe2 31 // Limitations:
Pawel Zarembski 0:01f31e923fe2 32 // - files must be contiguous
Pawel Zarembski 0:01f31e923fe2 33 // - data written cannot be read back
Pawel Zarembski 0:01f31e923fe2 34 // - data should only be read once
Pawel Zarembski 0:01f31e923fe2 35
Pawel Zarembski 0:01f31e923fe2 36 // FAT16 limitations +- safety margin
Pawel Zarembski 0:01f31e923fe2 37 #define FAT_CLUSTERS_MAX (65525 - 100)
Pawel Zarembski 0:01f31e923fe2 38 #define FAT_CLUSTERS_MIN (4086 + 100)
Pawel Zarembski 0:01f31e923fe2 39
Pawel Zarembski 0:01f31e923fe2 40 typedef struct {
Pawel Zarembski 0:01f31e923fe2 41 uint8_t boot_sector[11];
Pawel Zarembski 0:01f31e923fe2 42 /* DOS 2.0 BPB - Bios Parameter Block, 11 bytes */
Pawel Zarembski 0:01f31e923fe2 43 uint16_t bytes_per_sector;
Pawel Zarembski 0:01f31e923fe2 44 uint8_t sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 45 uint16_t reserved_logical_sectors;
Pawel Zarembski 0:01f31e923fe2 46 uint8_t num_fats;
Pawel Zarembski 0:01f31e923fe2 47 uint16_t max_root_dir_entries;
Pawel Zarembski 0:01f31e923fe2 48 uint16_t total_logical_sectors;
Pawel Zarembski 0:01f31e923fe2 49 uint8_t media_descriptor;
Pawel Zarembski 0:01f31e923fe2 50 uint16_t logical_sectors_per_fat;
Pawel Zarembski 0:01f31e923fe2 51 /* DOS 3.31 BPB - Bios Parameter Block, 12 bytes */
Pawel Zarembski 0:01f31e923fe2 52 uint16_t physical_sectors_per_track;
Pawel Zarembski 0:01f31e923fe2 53 uint16_t heads;
Pawel Zarembski 0:01f31e923fe2 54 uint32_t hidden_sectors;
Pawel Zarembski 0:01f31e923fe2 55 uint32_t big_sectors_on_drive;
Pawel Zarembski 0:01f31e923fe2 56 /* Extended BIOS Parameter Block, 26 bytes */
Pawel Zarembski 0:01f31e923fe2 57 uint8_t physical_drive_number;
Pawel Zarembski 0:01f31e923fe2 58 uint8_t not_used;
Pawel Zarembski 0:01f31e923fe2 59 uint8_t boot_record_signature;
Pawel Zarembski 0:01f31e923fe2 60 uint32_t volume_id;
Pawel Zarembski 0:01f31e923fe2 61 char volume_label[11];
Pawel Zarembski 0:01f31e923fe2 62 char file_system_type[8];
Pawel Zarembski 0:01f31e923fe2 63 /* bootstrap data in bytes 62-509 */
Pawel Zarembski 0:01f31e923fe2 64 uint8_t bootstrap[448];
Pawel Zarembski 0:01f31e923fe2 65 /* These entries in place of bootstrap code are the *nix partitions */
Pawel Zarembski 0:01f31e923fe2 66 //uint8_t partition_one[16];
Pawel Zarembski 0:01f31e923fe2 67 //uint8_t partition_two[16];
Pawel Zarembski 0:01f31e923fe2 68 //uint8_t partition_three[16];
Pawel Zarembski 0:01f31e923fe2 69 //uint8_t partition_four[16];
Pawel Zarembski 0:01f31e923fe2 70 /* Mandatory value at bytes 510-511, must be 0xaa55 */
Pawel Zarembski 0:01f31e923fe2 71 uint16_t signature;
Pawel Zarembski 0:01f31e923fe2 72 } __attribute__((packed)) mbr_t;
Pawel Zarembski 0:01f31e923fe2 73
Pawel Zarembski 0:01f31e923fe2 74 typedef struct file_allocation_table {
Pawel Zarembski 0:01f31e923fe2 75 uint8_t f[512];
Pawel Zarembski 0:01f31e923fe2 76 } file_allocation_table_t;
Pawel Zarembski 0:01f31e923fe2 77
Pawel Zarembski 0:01f31e923fe2 78 typedef struct FatDirectoryEntry {
Pawel Zarembski 0:01f31e923fe2 79 vfs_filename_t filename;
Pawel Zarembski 0:01f31e923fe2 80 uint8_t attributes;
Pawel Zarembski 0:01f31e923fe2 81 uint8_t reserved;
Pawel Zarembski 0:01f31e923fe2 82 uint8_t creation_time_ms;
Pawel Zarembski 0:01f31e923fe2 83 uint16_t creation_time;
Pawel Zarembski 0:01f31e923fe2 84 uint16_t creation_date;
Pawel Zarembski 0:01f31e923fe2 85 uint16_t accessed_date;
Pawel Zarembski 0:01f31e923fe2 86 uint16_t first_cluster_high_16;
Pawel Zarembski 0:01f31e923fe2 87 uint16_t modification_time;
Pawel Zarembski 0:01f31e923fe2 88 uint16_t modification_date;
Pawel Zarembski 0:01f31e923fe2 89 uint16_t first_cluster_low_16;
Pawel Zarembski 0:01f31e923fe2 90 uint32_t filesize;
Pawel Zarembski 0:01f31e923fe2 91 } __attribute__((packed)) FatDirectoryEntry_t;
Pawel Zarembski 0:01f31e923fe2 92 COMPILER_ASSERT(sizeof(FatDirectoryEntry_t) == 32);
Pawel Zarembski 0:01f31e923fe2 93
Pawel Zarembski 0:01f31e923fe2 94 // to save RAM all files must be in the first root dir entry (512 bytes)
Pawel Zarembski 0:01f31e923fe2 95 // but 2 actually exist on disc (32 entries) to accomodate hidden OS files,
Pawel Zarembski 0:01f31e923fe2 96 // folders and metadata
Pawel Zarembski 0:01f31e923fe2 97 typedef struct root_dir {
Pawel Zarembski 0:01f31e923fe2 98 FatDirectoryEntry_t f[32];
Pawel Zarembski 0:01f31e923fe2 99 } root_dir_t;
Pawel Zarembski 0:01f31e923fe2 100
Pawel Zarembski 0:01f31e923fe2 101 typedef struct virtual_media {
Pawel Zarembski 0:01f31e923fe2 102 vfs_read_cb_t read_cb;
Pawel Zarembski 0:01f31e923fe2 103 vfs_write_cb_t write_cb;
Pawel Zarembski 0:01f31e923fe2 104 uint32_t length;
Pawel Zarembski 0:01f31e923fe2 105 } virtual_media_t;
Pawel Zarembski 0:01f31e923fe2 106
Pawel Zarembski 0:01f31e923fe2 107 static uint32_t read_zero(uint32_t offset, uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 108 static void write_none(uint32_t offset, const uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 109
Pawel Zarembski 0:01f31e923fe2 110 static uint32_t read_mbr(uint32_t offset, uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 111 static uint32_t read_fat(uint32_t offset, uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 112 static uint32_t read_dir(uint32_t offset, uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 113 static void write_dir(uint32_t offset, const uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 114 static void file_change_cb_stub(const vfs_filename_t filename, vfs_file_change_t change,
Pawel Zarembski 0:01f31e923fe2 115 vfs_file_t file, vfs_file_t new_file_data);
Pawel Zarembski 0:01f31e923fe2 116 static uint32_t cluster_to_sector(uint32_t cluster_idx);
Pawel Zarembski 0:01f31e923fe2 117 static bool filename_valid(const vfs_filename_t filename);
Pawel Zarembski 0:01f31e923fe2 118 static bool filename_character_valid(char character);
Pawel Zarembski 0:01f31e923fe2 119
Pawel Zarembski 0:01f31e923fe2 120 // If sector size changes update comment below
Pawel Zarembski 0:01f31e923fe2 121 COMPILER_ASSERT(0x0200 == VFS_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 122 // If root directory size changes update max_root_dir_entries
Pawel Zarembski 0:01f31e923fe2 123 COMPILER_ASSERT(0x0020 == sizeof(root_dir_t) / sizeof(FatDirectoryEntry_t));
Pawel Zarembski 0:01f31e923fe2 124 static const mbr_t mbr_tmpl = {
Pawel Zarembski 0:01f31e923fe2 125 /*uint8_t[11]*/.boot_sector = {
Pawel Zarembski 0:01f31e923fe2 126 0xEB, 0x3C, 0x90,
Pawel Zarembski 0:01f31e923fe2 127 'M', 'S', 'D', '0', 'S', '4', '.', '1' // OEM Name in text (8 chars max)
Pawel Zarembski 0:01f31e923fe2 128 },
Pawel Zarembski 0:01f31e923fe2 129 /*uint16_t*/.bytes_per_sector = 0x0200, // 512 bytes per sector
Pawel Zarembski 0:01f31e923fe2 130 /*uint8_t */.sectors_per_cluster = 0x08, // 4k cluser
Pawel Zarembski 0:01f31e923fe2 131 /*uint16_t*/.reserved_logical_sectors = 0x0001, // mbr is 1 sector
Pawel Zarembski 0:01f31e923fe2 132 /*uint8_t */.num_fats = 0x02, // 2 FATs
Pawel Zarembski 0:01f31e923fe2 133 /*uint16_t*/.max_root_dir_entries = 0x0020, // 32 dir entries (max)
Pawel Zarembski 0:01f31e923fe2 134 /*uint16_t*/.total_logical_sectors = 0x1f50, // sector size * # of sectors = drive size
Pawel Zarembski 0:01f31e923fe2 135 /*uint8_t */.media_descriptor = 0xf8, // fixed disc = F8, removable = F0
Pawel Zarembski 0:01f31e923fe2 136 /*uint16_t*/.logical_sectors_per_fat = 0x0001, // FAT is 1k - ToDO:need to edit this
Pawel Zarembski 0:01f31e923fe2 137 /*uint16_t*/.physical_sectors_per_track = 0x0001, // flat
Pawel Zarembski 0:01f31e923fe2 138 /*uint16_t*/.heads = 0x0001, // flat
Pawel Zarembski 0:01f31e923fe2 139 /*uint32_t*/.hidden_sectors = 0x00000000, // before mbt, 0
Pawel Zarembski 0:01f31e923fe2 140 /*uint32_t*/.big_sectors_on_drive = 0x00000000, // 4k sector. not using large clusters
Pawel Zarembski 0:01f31e923fe2 141 /*uint8_t */.physical_drive_number = 0x00,
Pawel Zarembski 0:01f31e923fe2 142 /*uint8_t */.not_used = 0x00, // Current head. Linux tries to set this to 0x1
Pawel Zarembski 0:01f31e923fe2 143 /*uint8_t */.boot_record_signature = 0x29, // signature is present
Pawel Zarembski 0:01f31e923fe2 144 /*uint32_t*/.volume_id = 0x27021974, // serial number
Pawel Zarembski 0:01f31e923fe2 145 // needs to match the root dir label
Pawel Zarembski 0:01f31e923fe2 146 /*char[11]*/.volume_label = {'D', 'A', 'P', 'L', 'I', 'N', 'K', '-', 'D', 'N', 'D'},
Pawel Zarembski 0:01f31e923fe2 147 // unused by msft - just a label (FAT, FAT12, FAT16)
Pawel Zarembski 0:01f31e923fe2 148 /*char[8] */.file_system_type = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '},
Pawel Zarembski 0:01f31e923fe2 149
Pawel Zarembski 0:01f31e923fe2 150 /* BOOTSTRAP SOURCE CODE AND PAYLOAD GENERATOR
Pawel Zarembski 0:01f31e923fe2 151 * PRINTS OUT WARNING MESSAGE ON ACCIDENTAL BOOT FROM DAPLINK
Pawel Zarembski 0:01f31e923fe2 152 1 [BITS 16]
Pawel Zarembski 0:01f31e923fe2 153 2 %define BLSTART 0x3E
Pawel Zarembski 0:01f31e923fe2 154 3 %define BLLEN 448
Pawel Zarembski 0:01f31e923fe2 155 4
Pawel Zarembski 0:01f31e923fe2 156 5 00000000 FA cli
Pawel Zarembski 0:01f31e923fe2 157 6 00000001 B8C007 mov ax, 07C0h
Pawel Zarembski 0:01f31e923fe2 158 7 00000004 052001 add ax, 288
Pawel Zarembski 0:01f31e923fe2 159 8 00000007 8ED0 mov ss, ax
Pawel Zarembski 0:01f31e923fe2 160 9 00000009 BC0010 mov sp, 4096
Pawel Zarembski 0:01f31e923fe2 161 10 0000000C B8C007 mov ax, 07C0h
Pawel Zarembski 0:01f31e923fe2 162 11 0000000F 8ED8 mov ds, ax
Pawel Zarembski 0:01f31e923fe2 163 12 00000011 BE[6D00] mov si,message+BLSTART
Pawel Zarembski 0:01f31e923fe2 164 13 00000014 E80B00 call print
Pawel Zarembski 0:01f31e923fe2 165 14 00000017 EBFE jmp $
Pawel Zarembski 0:01f31e923fe2 166 15
Pawel Zarembski 0:01f31e923fe2 167 16 printc:
Pawel Zarembski 0:01f31e923fe2 168 17 00000019 B40E mov ah, 0x0E
Pawel Zarembski 0:01f31e923fe2 169 18 0000001B B700 mov bh, 0x00
Pawel Zarembski 0:01f31e923fe2 170 19 0000001D B307 mov bl, 0x07
Pawel Zarembski 0:01f31e923fe2 171 20 0000001F CD10 int 0x10
Pawel Zarembski 0:01f31e923fe2 172 21 00000021 C3 ret
Pawel Zarembski 0:01f31e923fe2 173 22
Pawel Zarembski 0:01f31e923fe2 174 23 print:
Pawel Zarembski 0:01f31e923fe2 175 24 nextc:
Pawel Zarembski 0:01f31e923fe2 176 25 00000022 8A04 mov al, [si]
Pawel Zarembski 0:01f31e923fe2 177 26 00000024 46 inc si
Pawel Zarembski 0:01f31e923fe2 178 27 00000025 08C0 or al, al
Pawel Zarembski 0:01f31e923fe2 179 28 00000027 7405 jz return
Pawel Zarembski 0:01f31e923fe2 180 29 00000029 E8EDFF call printc
Pawel Zarembski 0:01f31e923fe2 181 30 0000002C EBF4 jmp nextc
Pawel Zarembski 0:01f31e923fe2 182 31 return:
Pawel Zarembski 0:01f31e923fe2 183 32 0000002E C3 ret
Pawel Zarembski 0:01f31e923fe2 184 33
Pawel Zarembski 0:01f31e923fe2 185 34 0000002F 504C45415345205245- message db 'PLEASE REMOVE THE ARM MBED DAPLINK USB DEVICE AND REBOOT THE SYSTEM..', 0
Pawel Zarembski 0:01f31e923fe2 186 35 00000038 4D4F56452054484520-
Pawel Zarembski 0:01f31e923fe2 187 36 00000041 41524D204D42454420-
Pawel Zarembski 0:01f31e923fe2 188 37 0000004A 4441504C494E4B2055-
Pawel Zarembski 0:01f31e923fe2 189 38 00000053 534220444556494345-
Pawel Zarembski 0:01f31e923fe2 190 39 0000005C 20414E44205245424F-
Pawel Zarembski 0:01f31e923fe2 191 40 00000065 4F5420544845205359-
Pawel Zarembski 0:01f31e923fe2 192 41 0000006E 5354454D2E2E00
Pawel Zarembski 0:01f31e923fe2 193 42
Pawel Zarembski 0:01f31e923fe2 194 43 00000075 00<rept> times BLLEN-($-$$) db 0
Pawel Zarembski 0:01f31e923fe2 195
Pawel Zarembski 0:01f31e923fe2 196 USE BELOW SCRIPT TO COMPILE BOOTSTRAP AND GENERATE PAYLOAD:
Pawel Zarembski 0:01f31e923fe2 197 #!/usr/bin/env python
Pawel Zarembski 0:01f31e923fe2 198 import os
Pawel Zarembski 0:01f31e923fe2 199 os.system('nasm -f bin -o print.bin -l print.lst print.asm')
Pawel Zarembski 0:01f31e923fe2 200 print(open('print.lst','r').read())
Pawel Zarembski 0:01f31e923fe2 201 x=1
Pawel Zarembski 0:01f31e923fe2 202 for c in open('print.bin','rb').read():
Pawel Zarembski 0:01f31e923fe2 203 print('0x%02X, '%c, end='' if x % 16 else '\n')
Pawel Zarembski 0:01f31e923fe2 204 x += 1
Pawel Zarembski 0:01f31e923fe2 205 */
Pawel Zarembski 0:01f31e923fe2 206 /*uint8_t[448]*/.bootstrap = {
Pawel Zarembski 0:01f31e923fe2 207 0xFA, 0xB8, 0xC0, 0x07, 0x05, 0x20, 0x01, 0x8E, 0xD0, 0xBC, 0x00, 0x10, 0xB8, 0xC0, 0x07, 0x8E,
Pawel Zarembski 0:01f31e923fe2 208 0xD8, 0xBE, 0x6D, 0x00, 0xE8, 0x0B, 0x00, 0xEB, 0xFE, 0xB4, 0x0E, 0xB7, 0x00, 0xB3, 0x07, 0xCD,
Pawel Zarembski 0:01f31e923fe2 209 0x10, 0xC3, 0x8A, 0x04, 0x46, 0x08, 0xC0, 0x74, 0x05, 0xE8, 0xED, 0xFF, 0xEB, 0xF4, 0xC3, 0x50,
Pawel Zarembski 0:01f31e923fe2 210 0x4C, 0x45, 0x41, 0x53, 0x45, 0x20, 0x52, 0x45, 0x4D, 0x4F, 0x56, 0x45, 0x20, 0x54, 0x48, 0x45,
Pawel Zarembski 0:01f31e923fe2 211 0x20, 0x41, 0x52, 0x4D, 0x20, 0x4D, 0x42, 0x45, 0x44, 0x20, 0x44, 0x41, 0x50, 0x4C, 0x49, 0x4E,
Pawel Zarembski 0:01f31e923fe2 212 0x4B, 0x20, 0x55, 0x53, 0x42, 0x20, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x20, 0x41, 0x4E, 0x44,
Pawel Zarembski 0:01f31e923fe2 213 0x20, 0x52, 0x45, 0x42, 0x4F, 0x4F, 0x54, 0x20, 0x54, 0x48, 0x45, 0x20, 0x53, 0x59, 0x53, 0x54,
Pawel Zarembski 0:01f31e923fe2 214 0x45, 0x4D, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 215 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 219 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Pawel Zarembski 0:01f31e923fe2 235 },
Pawel Zarembski 0:01f31e923fe2 236 // Signature MUST be 0xAA55 to maintain compatibility (i.e. with Android).
Pawel Zarembski 0:01f31e923fe2 237 /*uint16_t*/.signature = 0xAA55,
Pawel Zarembski 0:01f31e923fe2 238 };
Pawel Zarembski 0:01f31e923fe2 239
Pawel Zarembski 0:01f31e923fe2 240 enum virtual_media_idx_t {
Pawel Zarembski 0:01f31e923fe2 241 MEDIA_IDX_MBR = 0,
Pawel Zarembski 0:01f31e923fe2 242 MEDIA_IDX_FAT1,
Pawel Zarembski 0:01f31e923fe2 243 MEDIA_IDX_FAT2,
Pawel Zarembski 0:01f31e923fe2 244 MEDIA_IDX_ROOT_DIR,
Pawel Zarembski 0:01f31e923fe2 245
Pawel Zarembski 0:01f31e923fe2 246 MEDIA_IDX_COUNT
Pawel Zarembski 0:01f31e923fe2 247 };
Pawel Zarembski 0:01f31e923fe2 248
Pawel Zarembski 0:01f31e923fe2 249 // Note - everything in virtual media must be a multiple of VFS_SECTOR_SIZE
Pawel Zarembski 0:01f31e923fe2 250 const virtual_media_t virtual_media_tmpl[] = {
Pawel Zarembski 0:01f31e923fe2 251 /* Read CB Write CB Region Size Region Name */
Pawel Zarembski 0:01f31e923fe2 252 { read_mbr, write_none, VFS_SECTOR_SIZE }, /* MBR */
Pawel Zarembski 0:01f31e923fe2 253 { read_fat, write_none, 0 /* Set at runtime */ }, /* FAT1 */
Pawel Zarembski 0:01f31e923fe2 254 { read_fat, write_none, 0 /* Set at runtime */ }, /* FAT2 */
Pawel Zarembski 0:01f31e923fe2 255 { read_dir, write_dir, VFS_SECTOR_SIZE * 2 }, /* Root Dir */
Pawel Zarembski 0:01f31e923fe2 256 /* Raw filesystem contents follow */
Pawel Zarembski 0:01f31e923fe2 257 };
Pawel Zarembski 0:01f31e923fe2 258 // Keep virtual_media_idx_t in sync with virtual_media_tmpl
Pawel Zarembski 0:01f31e923fe2 259 COMPILER_ASSERT(MEDIA_IDX_COUNT == ARRAY_SIZE(virtual_media_tmpl));
Pawel Zarembski 0:01f31e923fe2 260
Pawel Zarembski 0:01f31e923fe2 261 static const FatDirectoryEntry_t root_dir_entry = {
Pawel Zarembski 0:01f31e923fe2 262 /*uint8_t[11] */ .filename = {""},
Pawel Zarembski 0:01f31e923fe2 263 /*uint8_t */ .attributes = VFS_FILE_ATTR_VOLUME_LABEL | VFS_FILE_ATTR_ARCHIVE,
Pawel Zarembski 0:01f31e923fe2 264 /*uint8_t */ .reserved = 0x00,
Pawel Zarembski 0:01f31e923fe2 265 /*uint8_t */ .creation_time_ms = 0x00,
Pawel Zarembski 0:01f31e923fe2 266 /*uint16_t*/ .creation_time = 0x0000,
Pawel Zarembski 0:01f31e923fe2 267 /*uint16_t*/ .creation_date = 0x0000,
Pawel Zarembski 0:01f31e923fe2 268 /*uint16_t*/ .accessed_date = 0x0000,
Pawel Zarembski 0:01f31e923fe2 269 /*uint16_t*/ .first_cluster_high_16 = 0x0000,
Pawel Zarembski 0:01f31e923fe2 270 /*uint16_t*/ .modification_time = 0x8E41,
Pawel Zarembski 0:01f31e923fe2 271 /*uint16_t*/ .modification_date = 0x32bb,
Pawel Zarembski 0:01f31e923fe2 272 /*uint16_t*/ .first_cluster_low_16 = 0x0000,
Pawel Zarembski 0:01f31e923fe2 273 /*uint32_t*/ .filesize = 0x00000000
Pawel Zarembski 0:01f31e923fe2 274 };
Pawel Zarembski 0:01f31e923fe2 275
Pawel Zarembski 0:01f31e923fe2 276 static const FatDirectoryEntry_t dir_entry_tmpl = {
Pawel Zarembski 0:01f31e923fe2 277 /*uint8_t[11] */ .filename = {""},
Pawel Zarembski 0:01f31e923fe2 278 /*uint8_t */ .attributes = VFS_FILE_ATTR_READ_ONLY,
Pawel Zarembski 0:01f31e923fe2 279 /*uint8_t */ .reserved = 0x00,
Pawel Zarembski 0:01f31e923fe2 280 /*uint8_t */ .creation_time_ms = 0x00,
Pawel Zarembski 0:01f31e923fe2 281 /*uint16_t*/ .creation_time = 0x0000,
Pawel Zarembski 0:01f31e923fe2 282 /*uint16_t*/ .creation_date = 0x4876,
Pawel Zarembski 0:01f31e923fe2 283 /*uint16_t*/ .accessed_date = 0x4876,
Pawel Zarembski 0:01f31e923fe2 284 /*uint16_t*/ .first_cluster_high_16 = 0x0000,
Pawel Zarembski 0:01f31e923fe2 285 /*uint16_t*/ .modification_time = 0x83dc,
Pawel Zarembski 0:01f31e923fe2 286 /*uint16_t*/ .modification_date = 0x4876,
Pawel Zarembski 0:01f31e923fe2 287 /*uint16_t*/ .first_cluster_low_16 = 0x0000,
Pawel Zarembski 0:01f31e923fe2 288 /*uint32_t*/ .filesize = 0x00000000
Pawel Zarembski 0:01f31e923fe2 289 };
Pawel Zarembski 0:01f31e923fe2 290
Pawel Zarembski 0:01f31e923fe2 291 mbr_t mbr;
Pawel Zarembski 0:01f31e923fe2 292 file_allocation_table_t fat;
Pawel Zarembski 0:01f31e923fe2 293 virtual_media_t virtual_media[16];
Pawel Zarembski 0:01f31e923fe2 294 root_dir_t dir_current;
Pawel Zarembski 0:01f31e923fe2 295 uint8_t file_count;
Pawel Zarembski 0:01f31e923fe2 296 vfs_file_change_cb_t file_change_cb;
Pawel Zarembski 0:01f31e923fe2 297 uint32_t virtual_media_idx;
Pawel Zarembski 0:01f31e923fe2 298 uint32_t fat_idx;
Pawel Zarembski 0:01f31e923fe2 299 uint32_t dir_idx;
Pawel Zarembski 0:01f31e923fe2 300 uint32_t data_start;
Pawel Zarembski 0:01f31e923fe2 301
Pawel Zarembski 0:01f31e923fe2 302 // Virtual media must be larger than the template
Pawel Zarembski 0:01f31e923fe2 303 COMPILER_ASSERT(sizeof(virtual_media) > sizeof(virtual_media_tmpl));
Pawel Zarembski 0:01f31e923fe2 304
Pawel Zarembski 0:01f31e923fe2 305 static void write_fat(file_allocation_table_t *fat, uint32_t idx, uint16_t val)
Pawel Zarembski 0:01f31e923fe2 306 {
Pawel Zarembski 0:01f31e923fe2 307 uint32_t low_idx;
Pawel Zarembski 0:01f31e923fe2 308 uint32_t high_idx;
Pawel Zarembski 0:01f31e923fe2 309 low_idx = idx * 2 + 0;
Pawel Zarembski 0:01f31e923fe2 310 high_idx = idx * 2 + 1;
Pawel Zarembski 0:01f31e923fe2 311
Pawel Zarembski 0:01f31e923fe2 312 // Assert that this is still within the fat table
Pawel Zarembski 0:01f31e923fe2 313 if (high_idx >= ARRAY_SIZE(fat->f)) {
Pawel Zarembski 0:01f31e923fe2 314 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 315 return;
Pawel Zarembski 0:01f31e923fe2 316 }
Pawel Zarembski 0:01f31e923fe2 317
Pawel Zarembski 0:01f31e923fe2 318 fat->f[low_idx] = (val >> 0) & 0xFF;
Pawel Zarembski 0:01f31e923fe2 319 fat->f[high_idx] = (val >> 8) & 0xFF;
Pawel Zarembski 0:01f31e923fe2 320 }
Pawel Zarembski 0:01f31e923fe2 321
Pawel Zarembski 0:01f31e923fe2 322 void vfs_init(const vfs_filename_t drive_name, uint32_t disk_size)
Pawel Zarembski 0:01f31e923fe2 323 {
Pawel Zarembski 0:01f31e923fe2 324 uint32_t i;
Pawel Zarembski 0:01f31e923fe2 325 uint32_t num_clusters;
Pawel Zarembski 0:01f31e923fe2 326 uint32_t total_sectors;
Pawel Zarembski 0:01f31e923fe2 327 // Clear everything
Pawel Zarembski 0:01f31e923fe2 328 memset(&mbr, 0, sizeof(mbr));
Pawel Zarembski 0:01f31e923fe2 329 memset(&fat, 0, sizeof(fat));
Pawel Zarembski 0:01f31e923fe2 330 fat_idx = 0;
Pawel Zarembski 0:01f31e923fe2 331 memset(&virtual_media, 0, sizeof(virtual_media));
Pawel Zarembski 0:01f31e923fe2 332 memset(&dir_current, 0, sizeof(dir_current));
Pawel Zarembski 0:01f31e923fe2 333 dir_idx = 0;
Pawel Zarembski 0:01f31e923fe2 334 file_count = 0;
Pawel Zarembski 0:01f31e923fe2 335 file_change_cb = file_change_cb_stub;
Pawel Zarembski 0:01f31e923fe2 336 virtual_media_idx = 0;
Pawel Zarembski 0:01f31e923fe2 337 data_start = 0;
Pawel Zarembski 0:01f31e923fe2 338 // Initialize MBR
Pawel Zarembski 0:01f31e923fe2 339 memcpy(&mbr, &mbr_tmpl, sizeof(mbr_t));
Pawel Zarembski 0:01f31e923fe2 340 total_sectors = ((disk_size + KB(64)) / mbr.bytes_per_sector);
Pawel Zarembski 0:01f31e923fe2 341 // Make sure this is the right size for a FAT16 volume
Pawel Zarembski 0:01f31e923fe2 342 if (total_sectors < FAT_CLUSTERS_MIN * mbr.sectors_per_cluster) {
Pawel Zarembski 0:01f31e923fe2 343 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 344 total_sectors = FAT_CLUSTERS_MIN * mbr.sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 345 } else if (total_sectors > FAT_CLUSTERS_MAX * mbr.sectors_per_cluster) {
Pawel Zarembski 0:01f31e923fe2 346 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 347 total_sectors = FAT_CLUSTERS_MAX * mbr.sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 348 }
Pawel Zarembski 0:01f31e923fe2 349 if (total_sectors >= 0x10000) {
Pawel Zarembski 0:01f31e923fe2 350 mbr.total_logical_sectors = 0;
Pawel Zarembski 0:01f31e923fe2 351 mbr.big_sectors_on_drive = total_sectors;
Pawel Zarembski 0:01f31e923fe2 352 } else {
Pawel Zarembski 0:01f31e923fe2 353 mbr.total_logical_sectors = total_sectors;
Pawel Zarembski 0:01f31e923fe2 354 mbr.big_sectors_on_drive = 0;
Pawel Zarembski 0:01f31e923fe2 355 }
Pawel Zarembski 0:01f31e923fe2 356 // FAT table will likely be larger than needed, but this is allowed by the
Pawel Zarembski 0:01f31e923fe2 357 // fat specification
Pawel Zarembski 0:01f31e923fe2 358 num_clusters = total_sectors / mbr.sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 359 mbr.logical_sectors_per_fat = (num_clusters * 2 + VFS_SECTOR_SIZE - 1) / VFS_SECTOR_SIZE;
Pawel Zarembski 0:01f31e923fe2 360 // Initailize virtual media
Pawel Zarembski 0:01f31e923fe2 361 memcpy(&virtual_media, &virtual_media_tmpl, sizeof(virtual_media_tmpl));
Pawel Zarembski 0:01f31e923fe2 362 virtual_media[MEDIA_IDX_FAT1].length = VFS_SECTOR_SIZE * mbr.logical_sectors_per_fat;
Pawel Zarembski 0:01f31e923fe2 363 virtual_media[MEDIA_IDX_FAT2].length = VFS_SECTOR_SIZE * mbr.logical_sectors_per_fat;
Pawel Zarembski 0:01f31e923fe2 364 // Initialize indexes
Pawel Zarembski 0:01f31e923fe2 365 virtual_media_idx = MEDIA_IDX_COUNT;
Pawel Zarembski 0:01f31e923fe2 366 data_start = 0;
Pawel Zarembski 0:01f31e923fe2 367
Pawel Zarembski 0:01f31e923fe2 368 for (i = 0; i < ARRAY_SIZE(virtual_media_tmpl); i++) {
Pawel Zarembski 0:01f31e923fe2 369 data_start += virtual_media[i].length;
Pawel Zarembski 0:01f31e923fe2 370 }
Pawel Zarembski 0:01f31e923fe2 371
Pawel Zarembski 0:01f31e923fe2 372 // Initialize FAT
Pawel Zarembski 0:01f31e923fe2 373 fat_idx = 0;
Pawel Zarembski 0:01f31e923fe2 374 write_fat(&fat, fat_idx, 0xFFF8); // Media type "media_descriptor"
Pawel Zarembski 0:01f31e923fe2 375 fat_idx++;
Pawel Zarembski 0:01f31e923fe2 376 write_fat(&fat, fat_idx, 0xFFFF); // FAT12 - always 0xFFF (no meaning), FAT16 - dirty/clean (clean = 0xFFFF)
Pawel Zarembski 0:01f31e923fe2 377 fat_idx++;
Pawel Zarembski 0:01f31e923fe2 378 // Initialize root dir
Pawel Zarembski 0:01f31e923fe2 379 dir_idx = 0;
Pawel Zarembski 0:01f31e923fe2 380 dir_current.f[dir_idx] = root_dir_entry;
Pawel Zarembski 0:01f31e923fe2 381 memcpy(dir_current.f[dir_idx].filename, drive_name, sizeof(dir_current.f[0].filename));
Pawel Zarembski 0:01f31e923fe2 382 dir_idx++;
Pawel Zarembski 0:01f31e923fe2 383 }
Pawel Zarembski 0:01f31e923fe2 384
Pawel Zarembski 0:01f31e923fe2 385 uint32_t vfs_get_total_size()
Pawel Zarembski 0:01f31e923fe2 386 {
Pawel Zarembski 0:01f31e923fe2 387 uint32_t size;
Pawel Zarembski 0:01f31e923fe2 388 if (mbr.total_logical_sectors > 0) {
Pawel Zarembski 0:01f31e923fe2 389 size = mbr.total_logical_sectors * mbr.bytes_per_sector;
Pawel Zarembski 0:01f31e923fe2 390 } else if (mbr.big_sectors_on_drive > 0) {
Pawel Zarembski 0:01f31e923fe2 391 size = mbr.big_sectors_on_drive * mbr.bytes_per_sector;
Pawel Zarembski 0:01f31e923fe2 392 } else {
Pawel Zarembski 0:01f31e923fe2 393 size = 0;
Pawel Zarembski 0:01f31e923fe2 394 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 395 }
Pawel Zarembski 0:01f31e923fe2 396 return size;
Pawel Zarembski 0:01f31e923fe2 397 }
Pawel Zarembski 0:01f31e923fe2 398
Pawel Zarembski 0:01f31e923fe2 399 vfs_file_t vfs_create_file(const vfs_filename_t filename, vfs_read_cb_t read_cb, vfs_write_cb_t write_cb, uint32_t len)
Pawel Zarembski 0:01f31e923fe2 400 {
Pawel Zarembski 0:01f31e923fe2 401 uint32_t first_cluster;
Pawel Zarembski 0:01f31e923fe2 402 FatDirectoryEntry_t *de;
Pawel Zarembski 0:01f31e923fe2 403 uint32_t clusters;
Pawel Zarembski 0:01f31e923fe2 404 uint32_t cluster_size;
Pawel Zarembski 0:01f31e923fe2 405 uint32_t i;
Pawel Zarembski 0:01f31e923fe2 406 util_assert(filename_valid(filename));
Pawel Zarembski 0:01f31e923fe2 407 // Compute the number of clusters in the file
Pawel Zarembski 0:01f31e923fe2 408 cluster_size = mbr.bytes_per_sector * mbr.sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 409 clusters = (len + cluster_size - 1) / cluster_size;
Pawel Zarembski 0:01f31e923fe2 410 // Write the cluster chain to the fat table
Pawel Zarembski 0:01f31e923fe2 411 first_cluster = 0;
Pawel Zarembski 0:01f31e923fe2 412
Pawel Zarembski 0:01f31e923fe2 413 if (len > 0) {
Pawel Zarembski 0:01f31e923fe2 414 first_cluster = fat_idx;
Pawel Zarembski 0:01f31e923fe2 415
Pawel Zarembski 0:01f31e923fe2 416 for (i = 0; i < clusters - 1; i++) {
Pawel Zarembski 0:01f31e923fe2 417 write_fat(&fat, fat_idx, fat_idx + 1);
Pawel Zarembski 0:01f31e923fe2 418 fat_idx++;
Pawel Zarembski 0:01f31e923fe2 419 }
Pawel Zarembski 0:01f31e923fe2 420
Pawel Zarembski 0:01f31e923fe2 421 write_fat(&fat, fat_idx, 0xFFFF);
Pawel Zarembski 0:01f31e923fe2 422 fat_idx++;
Pawel Zarembski 0:01f31e923fe2 423 }
Pawel Zarembski 0:01f31e923fe2 424
Pawel Zarembski 0:01f31e923fe2 425 // Update directory entry
Pawel Zarembski 0:01f31e923fe2 426 if (dir_idx >= ARRAY_SIZE(dir_current.f)) {
Pawel Zarembski 0:01f31e923fe2 427 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 428 return VFS_FILE_INVALID;
Pawel Zarembski 0:01f31e923fe2 429 }
Pawel Zarembski 0:01f31e923fe2 430
Pawel Zarembski 0:01f31e923fe2 431 de = &dir_current.f[dir_idx];
Pawel Zarembski 0:01f31e923fe2 432 dir_idx++;
Pawel Zarembski 0:01f31e923fe2 433 memcpy(de, &dir_entry_tmpl, sizeof(dir_entry_tmpl));
Pawel Zarembski 0:01f31e923fe2 434 memcpy(de->filename, filename, 11);
Pawel Zarembski 0:01f31e923fe2 435 de->filesize = len;
Pawel Zarembski 0:01f31e923fe2 436 de->first_cluster_high_16 = (first_cluster >> 16) & 0xFFFF;
Pawel Zarembski 0:01f31e923fe2 437 de->first_cluster_low_16 = (first_cluster >> 0) & 0xFFFF;
Pawel Zarembski 0:01f31e923fe2 438
Pawel Zarembski 0:01f31e923fe2 439 // Update virtual media
Pawel Zarembski 0:01f31e923fe2 440 if (virtual_media_idx >= ARRAY_SIZE(virtual_media)) {
Pawel Zarembski 0:01f31e923fe2 441 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 442 return VFS_FILE_INVALID;
Pawel Zarembski 0:01f31e923fe2 443 }
Pawel Zarembski 0:01f31e923fe2 444
Pawel Zarembski 0:01f31e923fe2 445 virtual_media[virtual_media_idx].read_cb = read_zero;
Pawel Zarembski 0:01f31e923fe2 446 virtual_media[virtual_media_idx].write_cb = write_none;
Pawel Zarembski 0:01f31e923fe2 447
Pawel Zarembski 0:01f31e923fe2 448 if (0 != read_cb) {
Pawel Zarembski 0:01f31e923fe2 449 virtual_media[virtual_media_idx].read_cb = read_cb;
Pawel Zarembski 0:01f31e923fe2 450 }
Pawel Zarembski 0:01f31e923fe2 451
Pawel Zarembski 0:01f31e923fe2 452 if (0 != write_cb) {
Pawel Zarembski 0:01f31e923fe2 453 virtual_media[virtual_media_idx].write_cb = write_cb;
Pawel Zarembski 0:01f31e923fe2 454 }
Pawel Zarembski 0:01f31e923fe2 455
Pawel Zarembski 0:01f31e923fe2 456 virtual_media[virtual_media_idx].length = clusters * mbr.bytes_per_sector * mbr.sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 457 virtual_media_idx++;
Pawel Zarembski 0:01f31e923fe2 458 file_count += 1;
Pawel Zarembski 0:01f31e923fe2 459 return de;
Pawel Zarembski 0:01f31e923fe2 460 }
Pawel Zarembski 0:01f31e923fe2 461
Pawel Zarembski 0:01f31e923fe2 462 void vfs_file_set_attr(vfs_file_t file, vfs_file_attr_bit_t attr)
Pawel Zarembski 0:01f31e923fe2 463 {
Pawel Zarembski 0:01f31e923fe2 464 FatDirectoryEntry_t *de = file;
Pawel Zarembski 0:01f31e923fe2 465 de->attributes = attr;
Pawel Zarembski 0:01f31e923fe2 466 }
Pawel Zarembski 0:01f31e923fe2 467
Pawel Zarembski 0:01f31e923fe2 468 vfs_sector_t vfs_file_get_start_sector(vfs_file_t file)
Pawel Zarembski 0:01f31e923fe2 469 {
Pawel Zarembski 0:01f31e923fe2 470 FatDirectoryEntry_t *de = file;
Pawel Zarembski 0:01f31e923fe2 471
Pawel Zarembski 0:01f31e923fe2 472 if (vfs_file_get_size(file) == 0) {
Pawel Zarembski 0:01f31e923fe2 473 return VFS_INVALID_SECTOR;
Pawel Zarembski 0:01f31e923fe2 474 }
Pawel Zarembski 0:01f31e923fe2 475
Pawel Zarembski 0:01f31e923fe2 476 return cluster_to_sector(de->first_cluster_low_16);
Pawel Zarembski 0:01f31e923fe2 477 }
Pawel Zarembski 0:01f31e923fe2 478
Pawel Zarembski 0:01f31e923fe2 479 uint32_t vfs_file_get_size(vfs_file_t file)
Pawel Zarembski 0:01f31e923fe2 480 {
Pawel Zarembski 0:01f31e923fe2 481 FatDirectoryEntry_t *de = file;
Pawel Zarembski 0:01f31e923fe2 482 return de->filesize;
Pawel Zarembski 0:01f31e923fe2 483 }
Pawel Zarembski 0:01f31e923fe2 484
Pawel Zarembski 0:01f31e923fe2 485 vfs_file_attr_bit_t vfs_file_get_attr(vfs_file_t file)
Pawel Zarembski 0:01f31e923fe2 486 {
Pawel Zarembski 0:01f31e923fe2 487 FatDirectoryEntry_t *de = file;
Pawel Zarembski 0:01f31e923fe2 488 return (vfs_file_attr_bit_t)de->attributes;
Pawel Zarembski 0:01f31e923fe2 489 }
Pawel Zarembski 0:01f31e923fe2 490
Pawel Zarembski 0:01f31e923fe2 491 void vfs_set_file_change_callback(vfs_file_change_cb_t cb)
Pawel Zarembski 0:01f31e923fe2 492 {
Pawel Zarembski 0:01f31e923fe2 493 file_change_cb = cb;
Pawel Zarembski 0:01f31e923fe2 494 }
Pawel Zarembski 0:01f31e923fe2 495
Pawel Zarembski 0:01f31e923fe2 496 void vfs_read(uint32_t requested_sector, uint8_t *buf, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 497 {
Pawel Zarembski 0:01f31e923fe2 498 uint8_t i = 0;
Pawel Zarembski 0:01f31e923fe2 499 uint32_t current_sector;
Pawel Zarembski 0:01f31e923fe2 500 // Zero out the buffer
Pawel Zarembski 0:01f31e923fe2 501 memset(buf, 0, num_sectors * VFS_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 502 current_sector = 0;
Pawel Zarembski 0:01f31e923fe2 503
Pawel Zarembski 0:01f31e923fe2 504 for (i = 0; i < ARRAY_SIZE(virtual_media); i++) {
Pawel Zarembski 0:01f31e923fe2 505 uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE;
Pawel Zarembski 0:01f31e923fe2 506 uint32_t vm_start = current_sector;
Pawel Zarembski 0:01f31e923fe2 507 uint32_t vm_end = current_sector + vm_sectors;
Pawel Zarembski 0:01f31e923fe2 508
Pawel Zarembski 0:01f31e923fe2 509 // Data can be used in this sector
Pawel Zarembski 0:01f31e923fe2 510 if ((requested_sector >= vm_start) && (requested_sector < vm_end)) {
Pawel Zarembski 0:01f31e923fe2 511 uint32_t sector_offset;
Pawel Zarembski 0:01f31e923fe2 512 uint32_t sectors_to_write = vm_end - requested_sector;
Pawel Zarembski 0:01f31e923fe2 513 sectors_to_write = MIN(sectors_to_write, num_sectors);
Pawel Zarembski 0:01f31e923fe2 514 sector_offset = requested_sector - current_sector;
Pawel Zarembski 0:01f31e923fe2 515 virtual_media[i].read_cb(sector_offset, buf, sectors_to_write);
Pawel Zarembski 0:01f31e923fe2 516 // Update requested sector
Pawel Zarembski 0:01f31e923fe2 517 requested_sector += sectors_to_write;
Pawel Zarembski 0:01f31e923fe2 518 num_sectors -= sectors_to_write;
Pawel Zarembski 0:01f31e923fe2 519 }
Pawel Zarembski 0:01f31e923fe2 520
Pawel Zarembski 0:01f31e923fe2 521 // If there is no more data to be read then break
Pawel Zarembski 0:01f31e923fe2 522 if (num_sectors == 0) {
Pawel Zarembski 0:01f31e923fe2 523 break;
Pawel Zarembski 0:01f31e923fe2 524 }
Pawel Zarembski 0:01f31e923fe2 525
Pawel Zarembski 0:01f31e923fe2 526 // Move to the next virtual media entry
Pawel Zarembski 0:01f31e923fe2 527 current_sector += vm_sectors;
Pawel Zarembski 0:01f31e923fe2 528 }
Pawel Zarembski 0:01f31e923fe2 529 }
Pawel Zarembski 0:01f31e923fe2 530
Pawel Zarembski 0:01f31e923fe2 531 void vfs_write(uint32_t requested_sector, const uint8_t *buf, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 532 {
Pawel Zarembski 0:01f31e923fe2 533 uint8_t i = 0;
Pawel Zarembski 0:01f31e923fe2 534 uint32_t current_sector;
Pawel Zarembski 0:01f31e923fe2 535 current_sector = 0;
Pawel Zarembski 0:01f31e923fe2 536
Pawel Zarembski 0:01f31e923fe2 537 for (i = 0; i < virtual_media_idx; i++) {
Pawel Zarembski 0:01f31e923fe2 538 uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE;
Pawel Zarembski 0:01f31e923fe2 539 uint32_t vm_start = current_sector;
Pawel Zarembski 0:01f31e923fe2 540 uint32_t vm_end = current_sector + vm_sectors;
Pawel Zarembski 0:01f31e923fe2 541
Pawel Zarembski 0:01f31e923fe2 542 // Data can be used in this sector
Pawel Zarembski 0:01f31e923fe2 543 if ((requested_sector >= vm_start) && (requested_sector < vm_end)) {
Pawel Zarembski 0:01f31e923fe2 544 uint32_t sector_offset;
Pawel Zarembski 0:01f31e923fe2 545 uint32_t sectors_to_read = vm_end - requested_sector;
Pawel Zarembski 0:01f31e923fe2 546 sectors_to_read = MIN(sectors_to_read, num_sectors);
Pawel Zarembski 0:01f31e923fe2 547 sector_offset = requested_sector - current_sector;
Pawel Zarembski 0:01f31e923fe2 548 virtual_media[i].write_cb(sector_offset, buf, sectors_to_read);
Pawel Zarembski 0:01f31e923fe2 549 // Update requested sector
Pawel Zarembski 0:01f31e923fe2 550 requested_sector += sectors_to_read;
Pawel Zarembski 0:01f31e923fe2 551 num_sectors -= sectors_to_read;
Pawel Zarembski 0:01f31e923fe2 552 }
Pawel Zarembski 0:01f31e923fe2 553
Pawel Zarembski 0:01f31e923fe2 554 // If there is no more data to be read then break
Pawel Zarembski 0:01f31e923fe2 555 if (num_sectors == 0) {
Pawel Zarembski 0:01f31e923fe2 556 break;
Pawel Zarembski 0:01f31e923fe2 557 }
Pawel Zarembski 0:01f31e923fe2 558
Pawel Zarembski 0:01f31e923fe2 559 // Move to the next virtual media entry
Pawel Zarembski 0:01f31e923fe2 560 current_sector += vm_sectors;
Pawel Zarembski 0:01f31e923fe2 561 }
Pawel Zarembski 0:01f31e923fe2 562 }
Pawel Zarembski 0:01f31e923fe2 563
Pawel Zarembski 0:01f31e923fe2 564 static uint32_t read_zero(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 565 {
Pawel Zarembski 0:01f31e923fe2 566 uint32_t read_size = VFS_SECTOR_SIZE * num_sectors;
Pawel Zarembski 0:01f31e923fe2 567 memset(data, 0, read_size);
Pawel Zarembski 0:01f31e923fe2 568 return read_size;
Pawel Zarembski 0:01f31e923fe2 569 }
Pawel Zarembski 0:01f31e923fe2 570
Pawel Zarembski 0:01f31e923fe2 571 static void write_none(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 572 {
Pawel Zarembski 0:01f31e923fe2 573 // Do nothing
Pawel Zarembski 0:01f31e923fe2 574 }
Pawel Zarembski 0:01f31e923fe2 575
Pawel Zarembski 0:01f31e923fe2 576 static uint32_t read_mbr(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 577 {
Pawel Zarembski 0:01f31e923fe2 578 uint32_t read_size = sizeof(mbr_t);
Pawel Zarembski 0:01f31e923fe2 579 COMPILER_ASSERT(sizeof(mbr_t) <= VFS_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 580
Pawel Zarembski 0:01f31e923fe2 581 if (sector_offset != 0) {
Pawel Zarembski 0:01f31e923fe2 582 // Don't worry about reading other sectors
Pawel Zarembski 0:01f31e923fe2 583 return 0;
Pawel Zarembski 0:01f31e923fe2 584 }
Pawel Zarembski 0:01f31e923fe2 585
Pawel Zarembski 0:01f31e923fe2 586 memcpy(data, &mbr, read_size);
Pawel Zarembski 0:01f31e923fe2 587 return read_size;
Pawel Zarembski 0:01f31e923fe2 588 }
Pawel Zarembski 0:01f31e923fe2 589
Pawel Zarembski 0:01f31e923fe2 590 /* No need to handle writes to the mbr */
Pawel Zarembski 0:01f31e923fe2 591
Pawel Zarembski 0:01f31e923fe2 592 static uint32_t read_fat(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 593 {
Pawel Zarembski 0:01f31e923fe2 594 uint32_t read_size = sizeof(file_allocation_table_t);
Pawel Zarembski 0:01f31e923fe2 595 COMPILER_ASSERT(sizeof(file_allocation_table_t) <= VFS_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 596
Pawel Zarembski 0:01f31e923fe2 597 if (sector_offset != 0) {
Pawel Zarembski 0:01f31e923fe2 598 // Don't worry about reading other sectors
Pawel Zarembski 0:01f31e923fe2 599 return 0;
Pawel Zarembski 0:01f31e923fe2 600 }
Pawel Zarembski 0:01f31e923fe2 601
Pawel Zarembski 0:01f31e923fe2 602 memcpy(data, &fat, read_size);
Pawel Zarembski 0:01f31e923fe2 603 return read_size;
Pawel Zarembski 0:01f31e923fe2 604 }
Pawel Zarembski 0:01f31e923fe2 605
Pawel Zarembski 0:01f31e923fe2 606 /* No need to handle writes to the fat */
Pawel Zarembski 0:01f31e923fe2 607
Pawel Zarembski 0:01f31e923fe2 608 static uint32_t read_dir(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 609 {
Pawel Zarembski 0:01f31e923fe2 610 if ((sector_offset + num_sectors) * VFS_SECTOR_SIZE > sizeof(dir_current)) {
Pawel Zarembski 0:01f31e923fe2 611 // Trying to read too much of the root directory
Pawel Zarembski 0:01f31e923fe2 612 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 613 return 0;
Pawel Zarembski 0:01f31e923fe2 614 }
Pawel Zarembski 0:01f31e923fe2 615
Pawel Zarembski 0:01f31e923fe2 616 // Zero buffer data is VFS_SECTOR_SIZE max
Pawel Zarembski 0:01f31e923fe2 617 memset(data, 0, VFS_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 618
Pawel Zarembski 0:01f31e923fe2 619 if (sector_offset == 0) { //Handle the first 512 bytes
Pawel Zarembski 0:01f31e923fe2 620 // Copy data that is actually created in the directory
Pawel Zarembski 0:01f31e923fe2 621 memcpy(data, &dir_current.f[0], dir_idx*sizeof(FatDirectoryEntry_t));
Pawel Zarembski 0:01f31e923fe2 622 }
Pawel Zarembski 0:01f31e923fe2 623
Pawel Zarembski 0:01f31e923fe2 624 return num_sectors * VFS_SECTOR_SIZE;
Pawel Zarembski 0:01f31e923fe2 625 }
Pawel Zarembski 0:01f31e923fe2 626
Pawel Zarembski 0:01f31e923fe2 627 static void write_dir(uint32_t sector_offset, const uint8_t *data, uint32_t num_sectors)
Pawel Zarembski 0:01f31e923fe2 628 {
Pawel Zarembski 0:01f31e923fe2 629 FatDirectoryEntry_t *old_entry;
Pawel Zarembski 0:01f31e923fe2 630 FatDirectoryEntry_t *new_entry;
Pawel Zarembski 0:01f31e923fe2 631 uint32_t start_index;
Pawel Zarembski 0:01f31e923fe2 632 uint32_t num_entries;
Pawel Zarembski 0:01f31e923fe2 633 uint32_t i;
Pawel Zarembski 0:01f31e923fe2 634
Pawel Zarembski 0:01f31e923fe2 635 if ((sector_offset + num_sectors) * VFS_SECTOR_SIZE > sizeof(dir_current)) {
Pawel Zarembski 0:01f31e923fe2 636 // Trying to write too much of the root directory
Pawel Zarembski 0:01f31e923fe2 637 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 638 return;
Pawel Zarembski 0:01f31e923fe2 639 }
Pawel Zarembski 0:01f31e923fe2 640
Pawel Zarembski 0:01f31e923fe2 641 start_index = sector_offset * VFS_SECTOR_SIZE / sizeof(FatDirectoryEntry_t);
Pawel Zarembski 0:01f31e923fe2 642 num_entries = num_sectors * VFS_SECTOR_SIZE / sizeof(FatDirectoryEntry_t);
Pawel Zarembski 0:01f31e923fe2 643 old_entry = &dir_current.f[start_index];
Pawel Zarembski 0:01f31e923fe2 644 new_entry = (FatDirectoryEntry_t *)data;
Pawel Zarembski 0:01f31e923fe2 645 // If this is the first sector start at index 1 to get past drive name
Pawel Zarembski 0:01f31e923fe2 646 i = 0 == sector_offset ? 1 : 0;
Pawel Zarembski 0:01f31e923fe2 647
Pawel Zarembski 0:01f31e923fe2 648 for (; i < num_entries; i++) {
Pawel Zarembski 0:01f31e923fe2 649 bool same_name;
Pawel Zarembski 0:01f31e923fe2 650
Pawel Zarembski 0:01f31e923fe2 651 if (0 == memcmp(&old_entry[i], &new_entry[i], sizeof(FatDirectoryEntry_t))) {
Pawel Zarembski 0:01f31e923fe2 652 continue;
Pawel Zarembski 0:01f31e923fe2 653 }
Pawel Zarembski 0:01f31e923fe2 654
Pawel Zarembski 0:01f31e923fe2 655 // If were at this point then something has changed in the file
Pawel Zarembski 0:01f31e923fe2 656 same_name = (0 == memcmp(old_entry[i].filename, new_entry[i].filename, sizeof(new_entry[i].filename))) ? 1 : 0;
Pawel Zarembski 0:01f31e923fe2 657 // Changed
Pawel Zarembski 0:01f31e923fe2 658 file_change_cb(new_entry[i].filename, VFS_FILE_CHANGED, (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]);
Pawel Zarembski 0:01f31e923fe2 659
Pawel Zarembski 0:01f31e923fe2 660 // Deleted
Pawel Zarembski 0:01f31e923fe2 661 if (0xe5 == (uint8_t)new_entry[i].filename[0]) {
Pawel Zarembski 0:01f31e923fe2 662 file_change_cb(old_entry[i].filename, VFS_FILE_DELETED, (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]);
Pawel Zarembski 0:01f31e923fe2 663 continue;
Pawel Zarembski 0:01f31e923fe2 664 }
Pawel Zarembski 0:01f31e923fe2 665
Pawel Zarembski 0:01f31e923fe2 666 // Created
Pawel Zarembski 0:01f31e923fe2 667 if (!same_name && filename_valid(new_entry[i].filename)) {
Pawel Zarembski 0:01f31e923fe2 668 file_change_cb(new_entry[i].filename, VFS_FILE_CREATED, (vfs_file_t)&old_entry[i], (vfs_file_t)&new_entry[i]);
Pawel Zarembski 0:01f31e923fe2 669 continue;
Pawel Zarembski 0:01f31e923fe2 670 }
Pawel Zarembski 0:01f31e923fe2 671 }
Pawel Zarembski 0:01f31e923fe2 672
Pawel Zarembski 0:01f31e923fe2 673 memcpy(&dir_current.f[start_index], data, num_sectors * VFS_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 674 }
Pawel Zarembski 0:01f31e923fe2 675
Pawel Zarembski 0:01f31e923fe2 676 static void file_change_cb_stub(const vfs_filename_t filename, vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data)
Pawel Zarembski 0:01f31e923fe2 677 {
Pawel Zarembski 0:01f31e923fe2 678 // Do nothing
Pawel Zarembski 0:01f31e923fe2 679 }
Pawel Zarembski 0:01f31e923fe2 680
Pawel Zarembski 0:01f31e923fe2 681 static uint32_t cluster_to_sector(uint32_t cluster_idx)
Pawel Zarembski 0:01f31e923fe2 682 {
Pawel Zarembski 0:01f31e923fe2 683 uint32_t sectors_before_data = data_start / mbr.bytes_per_sector;
Pawel Zarembski 0:01f31e923fe2 684 return sectors_before_data + (cluster_idx - 2) * mbr.sectors_per_cluster;
Pawel Zarembski 0:01f31e923fe2 685 }
Pawel Zarembski 0:01f31e923fe2 686
Pawel Zarembski 0:01f31e923fe2 687 static bool filename_valid(const vfs_filename_t filename)
Pawel Zarembski 0:01f31e923fe2 688 {
Pawel Zarembski 0:01f31e923fe2 689 // Information on valid 8.3 filenames can be found in
Pawel Zarembski 0:01f31e923fe2 690 // the microsoft hardware whitepaper:
Pawel Zarembski 0:01f31e923fe2 691 //
Pawel Zarembski 0:01f31e923fe2 692 // Microsoft Extensible Firmware Initiative
Pawel Zarembski 0:01f31e923fe2 693 // FAT32 File System Specification
Pawel Zarembski 0:01f31e923fe2 694 // FAT: General Overview of On-Disk Format
Pawel Zarembski 0:01f31e923fe2 695 const char invalid_starting_chars[] = {
Pawel Zarembski 0:01f31e923fe2 696 0xE5, // Deleted
Pawel Zarembski 0:01f31e923fe2 697 0x00, // Deleted (and all following entries are free)
Pawel Zarembski 0:01f31e923fe2 698 0x20, // Space not allowed as first character
Pawel Zarembski 0:01f31e923fe2 699 };
Pawel Zarembski 0:01f31e923fe2 700 uint32_t i;
Pawel Zarembski 0:01f31e923fe2 701
Pawel Zarembski 0:01f31e923fe2 702 // Check for invalid starting characters
Pawel Zarembski 0:01f31e923fe2 703 for (i = 0; i < sizeof(invalid_starting_chars); i++) {
Pawel Zarembski 0:01f31e923fe2 704 if (invalid_starting_chars[i] == filename[0]) {
Pawel Zarembski 0:01f31e923fe2 705 return false;
Pawel Zarembski 0:01f31e923fe2 706 }
Pawel Zarembski 0:01f31e923fe2 707 }
Pawel Zarembski 0:01f31e923fe2 708
Pawel Zarembski 0:01f31e923fe2 709 // Make sure all the characters are valid
Pawel Zarembski 0:01f31e923fe2 710 for (i = 0; i < sizeof(vfs_filename_t); i++) {
Pawel Zarembski 0:01f31e923fe2 711 if (!filename_character_valid(filename[i])) {
Pawel Zarembski 0:01f31e923fe2 712 return false;
Pawel Zarembski 0:01f31e923fe2 713 }
Pawel Zarembski 0:01f31e923fe2 714 }
Pawel Zarembski 0:01f31e923fe2 715
Pawel Zarembski 0:01f31e923fe2 716 // All checks have passed so filename is valid
Pawel Zarembski 0:01f31e923fe2 717 return true;
Pawel Zarembski 0:01f31e923fe2 718 }
Pawel Zarembski 0:01f31e923fe2 719
Pawel Zarembski 0:01f31e923fe2 720 static bool filename_character_valid(char character)
Pawel Zarembski 0:01f31e923fe2 721 {
Pawel Zarembski 0:01f31e923fe2 722 const char invalid_chars[] = {0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C};
Pawel Zarembski 0:01f31e923fe2 723 uint32_t i;
Pawel Zarembski 0:01f31e923fe2 724
Pawel Zarembski 0:01f31e923fe2 725 // Lower case characters are not allowed
Pawel Zarembski 0:01f31e923fe2 726 if ((character >= 'a') && (character <= 'z')) {
Pawel Zarembski 0:01f31e923fe2 727 return false;
Pawel Zarembski 0:01f31e923fe2 728 }
Pawel Zarembski 0:01f31e923fe2 729
Pawel Zarembski 0:01f31e923fe2 730 // Values less than 0x20 are not allowed except 0x5
Pawel Zarembski 0:01f31e923fe2 731 if ((character < 0x20) && (character != 0x5)) {
Pawel Zarembski 0:01f31e923fe2 732 return false;
Pawel Zarembski 0:01f31e923fe2 733 }
Pawel Zarembski 0:01f31e923fe2 734
Pawel Zarembski 0:01f31e923fe2 735 // Check for special characters that are not allowed
Pawel Zarembski 0:01f31e923fe2 736 for (i = 0; i < sizeof(invalid_chars); i++) {
Pawel Zarembski 0:01f31e923fe2 737 if (invalid_chars[i] == character) {
Pawel Zarembski 0:01f31e923fe2 738 return false;
Pawel Zarembski 0:01f31e923fe2 739 }
Pawel Zarembski 0:01f31e923fe2 740 }
Pawel Zarembski 0:01f31e923fe2 741
Pawel Zarembski 0:01f31e923fe2 742 // All of the checks have passed so this is a valid file name character
Pawel Zarembski 0:01f31e923fe2 743 return true;
Pawel Zarembski 0:01f31e923fe2 744 }