22
22
#include <grub/types.h>
23
23
#include <grub/partition.h>
24
24
#include <grub/misc.h>
25
#include <grub/machine/time.h>
25
#include <grub/time.h>
26
26
#include <grub/file.h>
28
28
#define GRUB_CACHE_TIMEOUT 2
30
30
/* The last time the disk was used. */
31
static unsigned long grub_last_time = 0;
31
static grub_uint64_t grub_last_time = 0;
46
46
void (*grub_disk_firmware_fini) (void);
47
47
int grub_disk_firmware_is_tainted;
49
grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t,
50
struct grub_disk_ata_pass_through_parms *);
50
54
static unsigned long grub_disk_cache_hits;
51
55
static unsigned long grub_disk_cache_misses;
155
159
struct grub_disk_cache *cache;
157
grub_disk_cache_invalidate (dev_id, disk_id, sector);
159
161
index = grub_disk_cache_get_index (dev_id, disk_id, sector);
160
162
cache = grub_disk_cache_table + index;
165
grub_free (cache->data);
162
169
cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
163
170
if (! cache->data)
164
171
return grub_errno;
166
173
grub_memcpy (cache->data, data,
167
174
GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
168
175
cache->dev_id = dev_id;
202
209
grub_disk_dev_t p;
204
211
for (p = grub_disk_dev_list; p; p = p->next)
205
if ((p->iterate) (hook))
212
if (p->iterate && (p->iterate) (hook))
218
/* Return the location of the first ',', if any, which is not
221
find_part_sep (const char *name)
223
const char *p = name;
226
while ((c = *p++) != '\0')
228
if (c == '\\' && *p == ',')
212
237
grub_disk_open (const char *name)
215
240
grub_disk_t disk;
216
241
grub_disk_dev_t dev;
217
242
char *raw = (char *) name;
218
unsigned long current_time;
243
grub_uint64_t current_time;
220
245
grub_dprintf ("disk", "Opening `%s'...\n", name);
230
255
disk->name = grub_strdup (name);
231
256
if (! disk->name)
234
p = grub_strchr (name, ',');
259
p = find_part_sep (name);
237
262
grub_size_t len = p - name;
239
264
raw = grub_malloc (len + 1);
281
306
/* The cache will be invalidated about 2 seconds after a device was
283
current_time = grub_get_rtc ();
308
current_time = grub_get_time_ms ();
285
310
if (current_time > (grub_last_time
286
+ GRUB_CACHE_TIMEOUT * GRUB_TICKS_PER_SECOND))
311
+ GRUB_CACHE_TIMEOUT * 1000))
287
312
grub_disk_cache_invalidate_all ();
289
314
grub_last_time = current_time;
293
318
if (raw && raw != name)
315
340
(disk->dev->close) (disk);
317
342
/* Reset the timer. */
318
grub_last_time = grub_get_rtc ();
343
grub_last_time = grub_get_time_ms ();
320
345
grub_free (disk->partition);
321
346
grub_free ((void *) disk->name);
322
347
grub_free (disk);
350
/* This function performs three tasks:
351
- Make sectors disk relative from partition relative.
352
- Normalize offset to be less than the sector size.
353
- Verify that the range is inside the partition. */
325
354
static grub_err_t
326
grub_disk_check_range (grub_disk_t disk, grub_disk_addr_t *sector,
355
grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
327
356
grub_off_t *offset, grub_size_t size)
329
358
*sector += *offset >> GRUB_DISK_SECTOR_BITS;
330
359
*offset &= GRUB_DISK_SECTOR_SIZE - 1;
332
361
if (disk->partition)
334
363
grub_disk_addr_t start;
356
385
/* Read data from the disk. */
358
387
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
359
grub_off_t offset, grub_size_t size, char *buf)
388
grub_off_t offset, grub_size_t size, void *buf)
362
391
unsigned real_offset;
364
393
grub_dprintf ("disk", "Reading `%s'...\n", disk->name);
366
395
/* First of all, check if the region is within the disk. */
367
if (grub_disk_check_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
396
if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
369
398
grub_error_push ();
370
grub_dprintf ("disk", "Read out of range: sector 0x%llx.\n",
371
(unsigned long long) sector);
399
grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
400
(unsigned long long) sector, grub_errmsg);
372
401
grub_error_pop ();
373
402
return grub_errno;
376
405
real_offset = offset;
378
407
/* Allocate a temporary buffer. */
379
408
tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
465
494
grub_disk_addr_t s = sector;
466
495
grub_size_t l = len;
470
499
(disk->read_hook) (s, real_offset,
471
500
((l > GRUB_DISK_SECTOR_SIZE)
472
501
? GRUB_DISK_SECTOR_SIZE
475
504
if (l < GRUB_DISK_SECTOR_SIZE - real_offset)
479
508
l -= GRUB_DISK_SECTOR_SIZE - real_offset;
484
513
sector = start_sector + GRUB_DISK_CACHE_SIZE;
514
buf = (char *) buf + len;
492
521
grub_free (tmp_buf);
494
523
return grub_errno;
498
527
grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
499
grub_off_t offset, grub_size_t size, const char *buf)
528
grub_off_t offset, grub_size_t size, const void *buf)
501
530
unsigned real_offset;
503
532
grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
505
if (grub_disk_check_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
534
if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
508
537
real_offset = offset;
512
541
if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
514
543
char tmp_buf[GRUB_DISK_SECTOR_SIZE];
545
grub_partition_t part;
547
part = disk->partition;
517
549
if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf)
518
550
!= GRUB_ERR_NONE)
552
disk->partition = part;
555
disk->partition = part;
521
557
len = GRUB_DISK_SECTOR_SIZE - real_offset;
525
561
grub_memcpy (tmp_buf + real_offset, buf, len);
527
563
grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
542
578
len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
543
579
n = size >> GRUB_DISK_SECTOR_BITS;
545
581
if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
549
585
grub_disk_cache_invalidate (disk->dev->id, disk->id, sector++);
587
buf = (char *) buf + len;