⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs_disk.c

📁 pocket pc hx4700 bootloader
💻 C
字号:
/* *  GRUB  --  GRand Unified Bootloader *  Copyright (C) 2002,2003,2004,2006  Free Software Foundation, Inc. *  Copyright 2006 Pawel Kolodziejski - adopted to linux native bootloader * *  GRUB is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with GRUB; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "fs_types.h"/* The maximum number of disk caches.  */#define GRUB_DISK_CACHE_NUM	1021/* The size of a disk cache in sector units.  */#define GRUB_DISK_CACHE_SIZE	8#define GRUB_DISK_CACHE_BITS	3#define CACHE_ADDRESS		0xA3100400/* Disk cache.  */struct grub_disk_cache {	grub_disk_addr_t sector;	char *data;	int lock;};static unsigned grub_disk_cache_get_index(grub_disk_addr_t sector) {	return ((unsigned)(sector >> GRUB_DISK_CACHE_BITS)) % GRUB_DISK_CACHE_NUM;}static void grub_disk_cache_invalidate(grub_disk_addr_t sector) {	unsigned index;	struct grub_disk_cache *cache;	struct grub_disk_cache *grub_disk_cache_table = (struct grub_disk_cache *)CACHE_ADDRESS;	sector &= ~(GRUB_DISK_CACHE_SIZE - 1);	index = grub_disk_cache_get_index(sector);	cache = grub_disk_cache_table + index;	if (cache->sector == sector && cache->data) {		cache->lock = 1;		free(cache->data);		cache->data = 0;		cache->lock = 0;	}}void grub_disk_cache_invalidate_all(void) {	unsigned i;	struct grub_disk_cache *grub_disk_cache_table = (struct grub_disk_cache *)CACHE_ADDRESS;	for (i = 0; i < GRUB_DISK_CACHE_NUM; i++) {		struct grub_disk_cache *cache = grub_disk_cache_table + i;		if (cache->data && !cache->lock) {			free(cache->data);			cache->data = 0;		}	}}static char *grub_disk_cache_fetch(grub_disk_addr_t sector) {	struct grub_disk_cache *cache;	unsigned index;	struct grub_disk_cache *grub_disk_cache_table = (struct grub_disk_cache *)CACHE_ADDRESS;	index = grub_disk_cache_get_index(sector);	cache = grub_disk_cache_table + index;	if (cache->sector == sector) {		cache->lock = 1;		return cache->data;	}	return 0;}static void grub_disk_cache_unlock(grub_disk_addr_t sector) {	struct grub_disk_cache *cache;	unsigned index;	struct grub_disk_cache *grub_disk_cache_table = (struct grub_disk_cache *)CACHE_ADDRESS;	index = grub_disk_cache_get_index(sector);	cache = grub_disk_cache_table + index;	if (cache->sector == sector)		cache->lock = 0;}static grub_err_t grub_disk_cache_store(grub_disk_addr_t sector, const char *data) {	unsigned index;	struct grub_disk_cache *cache;	struct grub_disk_cache *grub_disk_cache_table = (struct grub_disk_cache *)CACHE_ADDRESS;	grub_disk_cache_invalidate(sector);	index = grub_disk_cache_get_index(sector);	cache = grub_disk_cache_table + index;	cache->data = (char *)malloc(GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);	if (!cache->data)		return grub_errno;	memcpy(cache->data, data, GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);	cache->sector = sector;	return GRUB_ERR_NONE;}static grub_err_t grub_disk_check_range(grub_disk_t disk, grub_disk_addr_t *sector,					grub_off_t *offset, grub_size_t size) {	*sector += *offset >> GRUB_DISK_SECTOR_BITS;	*offset &= GRUB_DISK_SECTOR_SIZE - 1; 	if (disk->pcount) {		grub_disk_addr_t start;		grub_uint64_t len;		start = disk->ptable[disk->cur_ptable].sector_start;		len = disk->ptable[disk->cur_ptable].sector_length;		if (*sector >= len				|| len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS))			return grub_error(GRUB_ERR_OUT_OF_RANGE, "out of partition");		*sector += start;	}	if (disk->total_sectors <= *sector			|| ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)			>> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector)		return grub_error(GRUB_ERR_OUT_OF_RANGE, "out of disk");	return GRUB_ERR_NONE;}static grub_err_t grub_raw_disk_read(grub_disk_t disk, grub_off_t sector, grub_off_t size, char *buf) {	while (size) {		if (sector >= disk->total_sectors)			return GRUB_ERR_OUT_OF_RANGE;		disk->read(buf, (int)sector);		buf += GRUB_DISK_SECTOR_SIZE;		sector++;		size--;	}	return GRUB_ERR_NONE;}/* Read data from the disk.  */grub_err_t grub_disk_read(grub_disk_t disk, grub_disk_addr_t sector, 			   grub_off_t offset, grub_size_t size, char *buf) {	char *tmp_buf;	unsigned real_offset;  	/* First of all, check if the region is within the disk.  */	if (grub_disk_check_range(disk, &sector, &offset, size) != GRUB_ERR_NONE)		return grub_errno;	real_offset = (unsigned)offset;  	/* Allocate a temporary buffer.  */	tmp_buf = (char *)malloc(GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);	if (!tmp_buf)		return grub_errno;	/* Until SIZE is zero...  */	while (size) {		char *data;		grub_disk_addr_t start_sector;		grub_size_t len;		grub_size_t pos;		/* For reading bulk data.  */		start_sector = sector & ~(GRUB_DISK_CACHE_SIZE - 1);		pos = (grub_size_t)(sector - start_sector) << GRUB_DISK_SECTOR_BITS;		len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS) - pos - real_offset);		if (len > size)			len = size;		/* Fetch the cache.  */		data = grub_disk_cache_fetch(start_sector);		if (data) {			/* Just copy it!  */			memcpy(buf, data + pos + real_offset, len);			grub_disk_cache_unlock(start_sector);		} else {			/* Otherwise read data from the disk actually.  */			if (grub_raw_disk_read(disk, start_sector, GRUB_DISK_CACHE_SIZE, tmp_buf) != GRUB_ERR_NONE) {				/* Uggh... Failed. Instead, just read necessary data.  */				unsigned num;				grub_set_error(GRUB_ERR_NONE);				/* If more data is required, no way.  */				if (pos + size >= (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS))					goto finish;				num = ((size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);				if (grub_raw_disk_read(disk, sector, num, tmp_buf))					goto finish;				memcpy(buf, tmp_buf + real_offset, size);				/* Call the read hook, if any.  */				if (disk->read_hook)				while (size) {					(disk->read_hook)(sector, real_offset, ((size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size));					sector++;					size -= GRUB_DISK_SECTOR_SIZE - real_offset;					real_offset = 0;				}				/* This must be the end.  */				goto finish;			}			/* Copy it and store it in the disk cache.  */			memcpy(buf, tmp_buf + pos + real_offset, len);			grub_disk_cache_store(start_sector, tmp_buf);		}		/* Call the read hook, if any.  */		if (disk->read_hook) {			grub_disk_addr_t s = sector;			grub_size_t l = len;			while (l) {				(disk->read_hook)(s, real_offset, ((l > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : l));				if (l < GRUB_DISK_SECTOR_SIZE - real_offset)					break;				s++;				l -= GRUB_DISK_SECTOR_SIZE - real_offset;				real_offset = 0;			}		}		sector = start_sector + GRUB_DISK_CACHE_SIZE;		buf += len;		size -= len;		real_offset = 0;	}finish:  	free(tmp_buf);	return grub_errno;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -