blob: 408fec76000f80d1793de6fca6e95e00053c9614 [file] [log] [blame]
wdenk591dda52002-11-18 00:14:45 +00001/*
2 * (C) Copyright 2002
Albert ARIBAUD60fbc8d2011-08-04 18:45:45 +02003 * Stäubli Faverges - <www.staubli.com>
wdenk591dda52002-11-18 00:14:45 +00004 * Pierre AUBERT p.aubert@staubli.com
5 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
wdenk591dda52002-11-18 00:14:45 +00007 */
8
9#include <common.h>
10#include <config.h>
11#include <malloc.h>
12
wdenk591dda52002-11-18 00:14:45 +000013#include "dos.h"
14#include "fdos.h"
15
16
17/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +000018 * fat_decode --
wdenk591dda52002-11-18 00:14:45 +000019 *-----------------------------------------------------------------------------
20 */
21unsigned int fat_decode (Fs_t *fs, unsigned int num)
22{
23 unsigned int start = num * 3 / 2;
24 unsigned char *address = fs -> fat_buf + start;
wdenk57b2d802003-06-27 21:31:46 +000025
wdenk591dda52002-11-18 00:14:45 +000026 if (num < 2 || start + 1 > (fs -> fat_len * SZ_STD_SECTOR))
wdenk57b2d802003-06-27 21:31:46 +000027 return 1;
28
wdenk591dda52002-11-18 00:14:45 +000029 if (num & 1)
wdenk57b2d802003-06-27 21:31:46 +000030 return ((address [1] & 0xff) << 4) | ((address [0] & 0xf0 ) >> 4);
wdenk591dda52002-11-18 00:14:45 +000031 else
wdenk57b2d802003-06-27 21:31:46 +000032 return ((address [1] & 0xf) << 8) | (address [0] & 0xff );
wdenk591dda52002-11-18 00:14:45 +000033}
34/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +000035 * check_fat --
wdenk591dda52002-11-18 00:14:45 +000036 *-----------------------------------------------------------------------------
37 */
38static int check_fat (Fs_t *fs)
39{
40 int i, f;
41
42 /* Cluster verification */
43 for (i = 3 ; i < fs -> num_clus; i++){
wdenk57b2d802003-06-27 21:31:46 +000044 f = fat_decode (fs, i);
45 if (f < FAT12_LAST && f > fs -> num_clus){
46 /* Wrong cluster number detected */
47 return (-1);
48 }
wdenk591dda52002-11-18 00:14:45 +000049 }
50 return (0);
51}
52/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +000053 * read_one_fat --
wdenk591dda52002-11-18 00:14:45 +000054 *-----------------------------------------------------------------------------
55 */
56static int read_one_fat (BootSector_t *boot, Fs_t *fs, int nfat)
57{
58 if (dev_read (fs -> fat_buf,
wdenk57b2d802003-06-27 21:31:46 +000059 (fs -> fat_start + nfat * fs -> fat_len),
60 fs -> fat_len) < 0) {
61 return (-1);
wdenk591dda52002-11-18 00:14:45 +000062 }
63
64 if (fs -> fat_buf [0] || fs -> fat_buf [1] || fs -> fat_buf [2]) {
wdenk57b2d802003-06-27 21:31:46 +000065 if ((fs -> fat_buf [0] != boot -> descr &&
66 (fs -> fat_buf [0] != 0xf9 || boot -> descr != MEDIA_STD)) ||
67 fs -> fat_buf [0] < MEDIA_STD){
68 /* Unknown Media */
69 return (-1);
70 }
71 if (fs -> fat_buf [1] != 0xff || fs -> fat_buf [2] != 0xff){
72 /* FAT doesn't start with good values */
73 return (-1);
74 }
wdenk591dda52002-11-18 00:14:45 +000075 }
76
77 if (fs -> num_clus >= FAT12_MAX_NB) {
wdenk57b2d802003-06-27 21:31:46 +000078 /* Too much clusters */
79 return (-1);
wdenk591dda52002-11-18 00:14:45 +000080 }
81
82 return check_fat (fs);
83}
84/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +000085 * read_fat --
wdenk591dda52002-11-18 00:14:45 +000086 *-----------------------------------------------------------------------------
87 */
88int read_fat (BootSector_t *boot, Fs_t *fs)
89{
90 unsigned int buflen;
91 int i;
92
93 /* Allocate Fat Buffer */
94 buflen = fs -> fat_len * SZ_STD_SECTOR;
95 if (fs -> fat_buf) {
wdenk57b2d802003-06-27 21:31:46 +000096 free (fs -> fat_buf);
wdenk591dda52002-11-18 00:14:45 +000097 }
98
99 if ((fs -> fat_buf = malloc (buflen)) == NULL) {
wdenk57b2d802003-06-27 21:31:46 +0000100 return (-1);
wdenk591dda52002-11-18 00:14:45 +0000101 }
102
103 /* Try to read each Fat */
104 for (i = 0; i< fs -> nb_fat; i++){
wdenk57b2d802003-06-27 21:31:46 +0000105 if (read_one_fat (boot, fs, i) == 0) {
106 /* Fat is OK */
107 fs -> num_fat = i;
108 break;
109 }
wdenk591dda52002-11-18 00:14:45 +0000110 }
111
112 if (i == fs -> nb_fat){
wdenk57b2d802003-06-27 21:31:46 +0000113 return (-1);
wdenk591dda52002-11-18 00:14:45 +0000114 }
wdenk57b2d802003-06-27 21:31:46 +0000115
wdenk591dda52002-11-18 00:14:45 +0000116 if (fs -> fat_len > (((fs -> num_clus + 2) *
wdenk57b2d802003-06-27 21:31:46 +0000117 (FAT_BITS / 4) -1 ) / 2 /
118 SZ_STD_SECTOR + 1)) {
119 return (-1);
wdenk591dda52002-11-18 00:14:45 +0000120 }
121 return (0);
122}