GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,13 @@
config FS_EXT4
bool "Enable ext4 filesystem support"
help
This provides support for reading images from the ext4 filesystem.
ext4 is a widely used general-purpose filesystem for Linux.
You can also enable CMD_EXT4 to get access to ext4 commands.
config EXT4_WRITE
bool "Enable ext4 filesystem write support"
depends on FS_EXT4
help
This provides support for creating and writing new files to an
existing ext4 filesystem partition.
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2006
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2003
# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
#
obj-y := ext4fs.o ext4_common.o dev.o
obj-$(CONFIG_EXT4_WRITE) += ext4_write.o ext4_journal.o crc16.o
@@ -0,0 +1,62 @@
/*
* crc16.c
*
* This source code is licensed under the GNU General Public License,
* Version 2. See the file COPYING for more details.
*/
#include <common.h>
#include <asm/byteorder.h>
#include <linux/stat.h>
#include "crc16.h"
/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
static __u16 const crc16_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
/**
* Compute the CRC-16 for the data buffer
*/
unsigned int ext2fs_crc16(unsigned int crc,
const void *buffer, unsigned int len)
{
const unsigned char *cp = buffer;
while (len--)
crc = (((crc >> 8) & 0xffU) ^
crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
return crc;
}
@@ -0,0 +1,16 @@
/*
* crc16.h - CRC-16 routine
* Implements the standard CRC-16:
* Width 16
* Poly 0x8005 (x16 + x15 + x2 + 1)
* Init 0
*
* Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
* This source code is licensed under the GNU General Public License,
* Version 2. See the file COPYING for more details.
*/
#ifndef __CRC16_H
#define __CRC16_H
extern unsigned int ext2fs_crc16(unsigned int crc,
const void *buffer, unsigned int len);
#endif
@@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2011 - 2012 Samsung Electronics
* EXT4 filesystem implementation in Uboot by
* Uma Shankar <uma.shankar@samsung.com>
* Manjunatha C Achar <a.manjunatha@samsung.com>
*
* made from existing ext2/dev.c file of Uboot
* (C) Copyright 2004
* esd gmbh <www.esd-electronics.com>
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
*
* based on code of fs/reiserfs/dev.c by
*
* (C) Copyright 2003 - 2004
* Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com>
*/
/*
* Changelog:
* 0.1 - Newly created file for ext4fs support. Taken from
* fs/ext2/dev.c file in uboot.
*/
#include <common.h>
#include <blk.h>
#include <config.h>
#include <fs_internal.h>
#include <ext4fs.h>
#include <ext_common.h>
#include "ext4_common.h"
lbaint_t part_offset;
static struct blk_desc *ext4fs_blk_desc;
static disk_partition_t *part_info;
void ext4fs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info)
{
assert(rbdd->blksz == (1 << rbdd->log2blksz));
ext4fs_blk_desc = rbdd;
get_fs()->dev_desc = rbdd;
part_info = info;
part_offset = info->start;
get_fs()->total_sect = ((uint64_t)info->size * info->blksz) >>
get_fs()->dev_desc->log2blksz;
}
int ext4fs_devread(lbaint_t sector, int byte_offset, int byte_len,
char *buffer)
{
return fs_devread(get_fs()->dev_desc, part_info, sector, byte_offset,
byte_len, buffer);
}
int ext4_read_superblock(char *buffer)
{
struct ext_filesystem *fs = get_fs();
int sect = SUPERBLOCK_START >> fs->dev_desc->log2blksz;
int off = SUPERBLOCK_START % fs->dev_desc->blksz;
return ext4fs_devread(sect, off, SUPERBLOCK_SIZE,
buffer);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2011 - 2012 Samsung Electronics
* EXT4 filesystem implementation in Uboot by
* Uma Shankar <uma.shankar@samsung.com>
* Manjunatha C Achar <a.manjunatha@samsung.com>
*
* ext4ls and ext4load : based on ext2 ls load support in Uboot.
*
* (C) Copyright 2004
* esd gmbh <www.esd-electronics.com>
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
*
* based on code from grub2 fs/ext2.c and fs/fshelp.c by
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
*
* ext4write : Based on generic ext4 protocol.
*/
#ifndef __EXT4_COMMON__
#define __EXT4_COMMON__
#include <ext_common.h>
#include <ext4fs.h>
#include <malloc.h>
#include <linux/errno.h>
#if defined(CONFIG_EXT4_WRITE)
#include "ext4_journal.h"
#include "crc16.h"
#endif
#define YES 1
#define NO 0
#define RECOVER 1
#define SCAN 0
#define S_IFLNK 0120000 /* symbolic link */
#define BLOCK_NO_ONE 1
#define SUPERBLOCK_START (2 * 512)
#define SUPERBLOCK_SIZE 1024
#define F_FILE 1
static inline void *zalloc(size_t size)
{
void *p = memalign(ARCH_DMA_MINALIGN, size);
memset(p, 0, size);
return p;
}
int ext4fs_read_inode(struct ext2_data *data, int ino,
struct ext2_inode *inode);
int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, loff_t len,
char *buf, loff_t *actread);
int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
struct ext2fs_node **foundnode, int expecttype);
int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
struct ext2fs_node **fnode, int *ftype);
#if defined(CONFIG_EXT4_WRITE)
uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n);
uint16_t ext4fs_checksum_update(unsigned int i);
int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags);
int ext4fs_update_parent_dentry(char *filename, int file_type);
uint32_t ext4fs_get_new_blk_no(void);
int ext4fs_get_new_inode_no(void);
void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer,
int index);
int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index);
int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index);
void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index);
int ext4fs_iget(int inode_no, struct ext2_inode *inode);
void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
unsigned int total_remaining_blocks,
unsigned int *total_no_of_block);
void put_ext4(uint64_t off, const void *buf, uint32_t size);
struct ext2_block_group *ext4fs_get_group_descriptor
(const struct ext_filesystem *fs, uint32_t bg_idx);
uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg,
const struct ext_filesystem *fs);
uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg,
const struct ext_filesystem *fs);
uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg,
const struct ext_filesystem *fs);
uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb);
void ext4fs_sb_set_free_blocks(struct ext2_sblock *sb, uint64_t free_blocks);
uint32_t ext4fs_bg_get_free_blocks(const struct ext2_block_group *bg,
const struct ext_filesystem *fs);
#endif
#endif
@@ -0,0 +1,666 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2011 - 2012 Samsung Electronics
* EXT4 filesystem implementation in Uboot by
* Uma Shankar <uma.shankar@samsung.com>
* Manjunatha C Achar <a.manjunatha@samsung.com>
*
* Journal data structures and headers for Journaling feature of ext4
* have been referred from JBD2 (Journaling Block device 2)
* implementation in Linux Kernel.
* Written by Stephen C. Tweedie <sct@redhat.com>
*
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
*/
#include <common.h>
#include <ext4fs.h>
#include <malloc.h>
#include <ext_common.h>
#include "ext4_common.h"
static struct revoke_blk_list *revk_blk_list;
static struct revoke_blk_list *prev_node;
static int first_node = true;
int gindex;
int gd_index;
int jrnl_blk_idx;
struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
int ext4fs_init_journal(void)
{
int i;
char *temp = NULL;
struct ext_filesystem *fs = get_fs();
/* init globals */
revk_blk_list = NULL;
prev_node = NULL;
gindex = 0;
gd_index = 0;
jrnl_blk_idx = 1;
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
journal_ptr[i] = zalloc(sizeof(struct journal_log));
if (!journal_ptr[i])
goto fail;
dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
if (!dirty_block_ptr[i])
goto fail;
journal_ptr[i]->buf = NULL;
journal_ptr[i]->blknr = -1;
dirty_block_ptr[i]->buf = NULL;
dirty_block_ptr[i]->blknr = -1;
}
if (fs->blksz == 4096) {
temp = zalloc(fs->blksz);
if (!temp)
goto fail;
journal_ptr[gindex]->buf = zalloc(fs->blksz);
if (!journal_ptr[gindex]->buf)
goto fail;
ext4fs_devread(0, 0, fs->blksz, temp);
memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
journal_ptr[gindex++]->blknr = 0;
free(temp);
} else {
journal_ptr[gindex]->buf = zalloc(fs->blksz);
if (!journal_ptr[gindex]->buf)
goto fail;
memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
journal_ptr[gindex++]->blknr = 1;
}
/* Check the file system state using journal super block */
if (ext4fs_check_journal_state(SCAN))
goto fail;
/* Check the file system state using journal super block */
if (ext4fs_check_journal_state(RECOVER))
goto fail;
return 0;
fail:
return -1;
}
void ext4fs_dump_metadata(void)
{
struct ext_filesystem *fs = get_fs();
int i;
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (dirty_block_ptr[i]->blknr == -1)
break;
put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
(uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
fs->blksz);
}
}
void ext4fs_free_journal(void)
{
int i;
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (dirty_block_ptr[i]->blknr == -1)
break;
if (dirty_block_ptr[i]->buf)
free(dirty_block_ptr[i]->buf);
}
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i]->blknr == -1)
break;
if (journal_ptr[i]->buf)
free(journal_ptr[i]->buf);
}
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i])
free(journal_ptr[i]);
if (dirty_block_ptr[i])
free(dirty_block_ptr[i]);
}
gindex = 0;
gd_index = 0;
jrnl_blk_idx = 1;
}
int ext4fs_log_gdt(char *gd_table)
{
struct ext_filesystem *fs = get_fs();
short i;
long int var = fs->gdtable_blkno;
for (i = 0; i < fs->no_blk_pergdt; i++) {
journal_ptr[gindex]->buf = zalloc(fs->blksz);
if (!journal_ptr[gindex]->buf)
return -ENOMEM;
memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
gd_table += fs->blksz;
journal_ptr[gindex++]->blknr = var++;
}
return 0;
}
/*
* This function stores the backup copy of meta data in RAM
* journal_buffer -- Buffer containing meta data
* blknr -- Block number on disk of the meta data buffer
*/
int ext4fs_log_journal(char *journal_buffer, uint32_t blknr)
{
struct ext_filesystem *fs = get_fs();
short i;
if (!journal_buffer) {
printf("Invalid input arguments %s\n", __func__);
return -EINVAL;
}
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i]->blknr == -1)
break;
if (journal_ptr[i]->blknr == blknr)
return 0;
}
journal_ptr[gindex]->buf = zalloc(fs->blksz);
if (!journal_ptr[gindex]->buf)
return -ENOMEM;
memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
journal_ptr[gindex++]->blknr = blknr;
return 0;
}
/*
* This function stores the modified meta data in RAM
* metadata_buffer -- Buffer containing meta data
* blknr -- Block number on disk of the meta data buffer
*/
int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
{
struct ext_filesystem *fs = get_fs();
if (!metadata_buffer) {
printf("Invalid input arguments %s\n", __func__);
return -EINVAL;
}
if (dirty_block_ptr[gd_index]->buf)
assert(dirty_block_ptr[gd_index]->blknr == blknr);
else
dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
if (!dirty_block_ptr[gd_index]->buf)
return -ENOMEM;
memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
dirty_block_ptr[gd_index++]->blknr = blknr;
return 0;
}
void print_revoke_blks(char *revk_blk)
{
int offset;
int max;
long int blocknr;
struct journal_revoke_header_t *header;
if (revk_blk == NULL)
return;
header = (struct journal_revoke_header_t *) revk_blk;
offset = sizeof(struct journal_revoke_header_t);
max = be32_to_cpu(header->r_count);
printf("total bytes %d\n", max);
while (offset < max) {
blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
printf("revoke blknr is %ld\n", blocknr);
offset += 4;
}
}
static struct revoke_blk_list *_get_node(void)
{
struct revoke_blk_list *tmp_node;
tmp_node = zalloc(sizeof(struct revoke_blk_list));
if (tmp_node == NULL)
return NULL;
tmp_node->content = NULL;
tmp_node->next = NULL;
return tmp_node;
}
void ext4fs_push_revoke_blk(char *buffer)
{
struct revoke_blk_list *node = NULL;
struct ext_filesystem *fs = get_fs();
if (buffer == NULL) {
printf("buffer ptr is NULL\n");
return;
}
node = _get_node();
if (!node) {
printf("_get_node: malloc failed\n");
return;
}
node->content = zalloc(fs->blksz);
if (node->content == NULL)
return;
memcpy(node->content, buffer, fs->blksz);
if (first_node == true) {
revk_blk_list = node;
prev_node = node;
first_node = false;
} else {
prev_node->next = node;
prev_node = node;
}
}
void ext4fs_free_revoke_blks(void)
{
struct revoke_blk_list *tmp_node = revk_blk_list;
struct revoke_blk_list *next_node = NULL;
while (tmp_node != NULL) {
if (tmp_node->content)
free(tmp_node->content);
tmp_node = tmp_node->next;
}
tmp_node = revk_blk_list;
while (tmp_node != NULL) {
next_node = tmp_node->next;
free(tmp_node);
tmp_node = next_node;
}
revk_blk_list = NULL;
prev_node = NULL;
first_node = true;
}
int check_blknr_for_revoke(long int blknr, int sequence_no)
{
struct journal_revoke_header_t *header;
int offset;
int max;
long int blocknr;
char *revk_blk;
struct revoke_blk_list *tmp_revk_node = revk_blk_list;
while (tmp_revk_node != NULL) {
revk_blk = tmp_revk_node->content;
header = (struct journal_revoke_header_t *) revk_blk;
if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
offset = sizeof(struct journal_revoke_header_t);
max = be32_to_cpu(header->r_count);
while (offset < max) {
blocknr = be32_to_cpu(*((__be32 *)
(revk_blk + offset)));
if (blocknr == blknr)
goto found;
offset += 4;
}
}
tmp_revk_node = tmp_revk_node->next;
}
return -1;
found:
return 0;
}
/*
* This function parses the journal blocks and replays the
* suceessful transactions. A transaction is successfull
* if commit block is found for a descriptor block
* The tags in descriptor block contain the disk block
* numbers of the metadata to be replayed
*/
void recover_transaction(int prev_desc_logical_no)
{
struct ext2_inode inode_journal;
struct ext_filesystem *fs = get_fs();
struct journal_header_t *jdb;
long int blknr;
char *p_jdb;
int ofs, flags;
int i;
struct ext3_journal_block_tag *tag;
char *temp_buff = zalloc(fs->blksz);
char *metadata_buff = zalloc(fs->blksz);
if (!temp_buff || !metadata_buff)
goto fail;
i = prev_desc_logical_no;
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
(struct ext2_inode *)&inode_journal);
blknr = read_allocated_block((struct ext2_inode *)
&inode_journal, i, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
p_jdb = (char *)temp_buff;
jdb = (struct journal_header_t *) temp_buff;
ofs = sizeof(struct journal_header_t);
do {
tag = (struct ext3_journal_block_tag *)(p_jdb + ofs);
ofs += sizeof(struct ext3_journal_block_tag);
if (ofs > fs->blksz)
break;
flags = be32_to_cpu(tag->flags);
if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
ofs += 16;
i++;
debug("\t\ttag %u\n", be32_to_cpu(tag->block));
if (revk_blk_list != NULL) {
if (check_blknr_for_revoke(be32_to_cpu(tag->block),
be32_to_cpu(jdb->h_sequence)) == 0)
continue;
}
blknr = read_allocated_block(&inode_journal, i, NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
fs->blksz, metadata_buff);
put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
metadata_buff, (uint32_t) fs->blksz);
} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
fail:
free(temp_buff);
free(metadata_buff);
}
void print_jrnl_status(int recovery_flag)
{
if (recovery_flag == RECOVER)
printf("Journal Recovery Completed\n");
else
printf("Journal Scan Completed\n");
}
int ext4fs_check_journal_state(int recovery_flag)
{
int i;
int DB_FOUND = NO;
long int blknr;
int transaction_state = TRANSACTION_COMPLETE;
int prev_desc_logical_no = 0;
int curr_desc_logical_no = 0;
int ofs, flags;
struct ext2_inode inode_journal;
struct journal_superblock_t *jsb = NULL;
struct journal_header_t *jdb = NULL;
char *p_jdb = NULL;
struct ext3_journal_block_tag *tag = NULL;
char *temp_buff = NULL;
char *temp_buff1 = NULL;
struct ext_filesystem *fs = get_fs();
temp_buff = zalloc(fs->blksz);
if (!temp_buff)
return -ENOMEM;
temp_buff1 = zalloc(fs->blksz);
if (!temp_buff1) {
free(temp_buff);
return -ENOMEM;
}
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
NULL);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
if (recovery_flag == RECOVER)
printf("Recovery required\n");
} else {
if (recovery_flag == RECOVER)
printf("File System is consistent\n");
goto end;
}
if (be32_to_cpu(jsb->s_start) == 0)
goto end;
if (!(jsb->s_feature_compat &
cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
jsb->s_feature_compat |=
cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
i = be32_to_cpu(jsb->s_first);
while (1) {
blknr = read_allocated_block(&inode_journal, i, NULL);
memset(temp_buff1, '\0', fs->blksz);
ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
0, fs->blksz, temp_buff1);
jdb = (struct journal_header_t *) temp_buff1;
if (be32_to_cpu(jdb->h_blocktype) ==
EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
if (be32_to_cpu(jdb->h_sequence) !=
be32_to_cpu(jsb->s_sequence)) {
print_jrnl_status(recovery_flag);
break;
}
curr_desc_logical_no = i;
if (transaction_state == TRANSACTION_COMPLETE)
transaction_state = TRANSACTION_RUNNING;
else
return -1;
p_jdb = (char *)temp_buff1;
ofs = sizeof(struct journal_header_t);
do {
tag = (struct ext3_journal_block_tag *)
(p_jdb + ofs);
ofs += sizeof(struct ext3_journal_block_tag);
if (ofs > fs->blksz)
break;
flags = be32_to_cpu(tag->flags);
if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
ofs += 16;
i++;
debug("\t\ttag %u\n", be32_to_cpu(tag->block));
} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
i++;
DB_FOUND = YES;
} else if (be32_to_cpu(jdb->h_blocktype) ==
EXT3_JOURNAL_COMMIT_BLOCK) {
if (be32_to_cpu(jdb->h_sequence) !=
be32_to_cpu(jsb->s_sequence)) {
print_jrnl_status(recovery_flag);
break;
}
if (transaction_state == TRANSACTION_RUNNING ||
(DB_FOUND == NO)) {
transaction_state = TRANSACTION_COMPLETE;
i++;
jsb->s_sequence =
cpu_to_be32(be32_to_cpu(
jsb->s_sequence) + 1);
}
prev_desc_logical_no = curr_desc_logical_no;
if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
recover_transaction(prev_desc_logical_no);
DB_FOUND = NO;
} else if (be32_to_cpu(jdb->h_blocktype) ==
EXT3_JOURNAL_REVOKE_BLOCK) {
if (be32_to_cpu(jdb->h_sequence) !=
be32_to_cpu(jsb->s_sequence)) {
print_jrnl_status(recovery_flag);
break;
}
if (recovery_flag == SCAN)
ext4fs_push_revoke_blk((char *)jdb);
i++;
} else {
debug("Else Case\n");
if (be32_to_cpu(jdb->h_sequence) !=
be32_to_cpu(jsb->s_sequence)) {
print_jrnl_status(recovery_flag);
break;
}
}
}
end:
if (recovery_flag == RECOVER) {
uint32_t new_feature_incompat;
jsb->s_start = cpu_to_be32(1);
jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
/* get the superblock */
ext4_read_superblock((char *)fs->sb);
new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
/* Update the super block */
put_ext4((uint64_t) (SUPERBLOCK_SIZE),
(struct ext2_sblock *)fs->sb,
(uint32_t) SUPERBLOCK_SIZE);
ext4_read_superblock((char *)fs->sb);
blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK, NULL);
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
(struct journal_superblock_t *)temp_buff,
(uint32_t) fs->blksz);
ext4fs_free_revoke_blks();
}
free(temp_buff);
free(temp_buff1);
return 0;
}
static void update_descriptor_block(long int blknr)
{
int i;
long int jsb_blknr;
struct journal_header_t jdb;
struct ext3_journal_block_tag tag;
struct ext2_inode inode_journal;
struct journal_superblock_t *jsb = NULL;
char *buf = NULL;
char *temp = NULL;
struct ext_filesystem *fs = get_fs();
char *temp_buff = zalloc(fs->blksz);
if (!temp_buff)
return;
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
jsb_blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
jdb.h_sequence = jsb->s_sequence;
buf = zalloc(fs->blksz);
if (!buf) {
free(temp_buff);
return;
}
temp = buf;
memcpy(buf, &jdb, sizeof(struct journal_header_t));
temp += sizeof(struct journal_header_t);
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i]->blknr == -1)
break;
tag.block = cpu_to_be32(journal_ptr[i]->blknr);
tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
temp = temp + sizeof(struct ext3_journal_block_tag);
}
tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
sizeof(struct ext3_journal_block_tag));
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
free(temp_buff);
free(buf);
}
static void update_commit_block(long int blknr)
{
struct journal_header_t jdb;
struct ext_filesystem *fs = get_fs();
char *buf = NULL;
struct ext2_inode inode_journal;
struct journal_superblock_t *jsb;
long int jsb_blknr;
char *temp_buff = zalloc(fs->blksz);
if (!temp_buff)
return;
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
&inode_journal);
jsb_blknr = read_allocated_block(&inode_journal,
EXT2_JOURNAL_SUPERBLOCK, NULL);
ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
temp_buff);
jsb = (struct journal_superblock_t *) temp_buff;
jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
jdb.h_sequence = jsb->s_sequence;
buf = zalloc(fs->blksz);
if (!buf) {
free(temp_buff);
return;
}
memcpy(buf, &jdb, sizeof(struct journal_header_t));
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
free(temp_buff);
free(buf);
}
void ext4fs_update_journal(void)
{
struct ext2_inode inode_journal;
struct ext_filesystem *fs = get_fs();
long int blknr;
int i;
if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
return;
ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_descriptor_block(blknr);
for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
if (journal_ptr[i]->blknr == -1)
break;
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
NULL);
put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
journal_ptr[i]->buf, fs->blksz);
}
blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
update_commit_block(blknr);
printf("update journal finished\n");
}
@@ -0,0 +1,127 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2011 - 2012 Samsung Electronics
* EXT4 filesystem implementation in Uboot by
* Uma Shankar <uma.shankar@samsung.com>
* Manjunatha C Achar <a.manjunatha@samsung.com>
*
* Journal data structures and headers for Journaling feature of ext4
* have been referred from JBD2 (Journaling Block device 2)
* implementation in Linux Kernel.
*
* Written by Stephen C. Tweedie <sct@redhat.com>
*
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
*/
#ifndef __EXT4_JRNL__
#define __EXT4_JRNL__
#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT2_JOURNAL_INO 8 /* Journal inode */
#define EXT2_JOURNAL_SUPERBLOCK 0 /* Journal Superblock number */
#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001
#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
#define TRANSACTION_RUNNING 1
#define TRANSACTION_COMPLETE 0
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
#define EXT3_JOURNAL_COMMIT_BLOCK 2
#define EXT3_JOURNAL_SUPERBLOCK_V1 3
#define EXT3_JOURNAL_SUPERBLOCK_V2 4
#define EXT3_JOURNAL_REVOKE_BLOCK 5
#define EXT3_JOURNAL_FLAG_ESCAPE 1
#define EXT3_JOURNAL_FLAG_SAME_UUID 2
#define EXT3_JOURNAL_FLAG_DELETED 4
#define EXT3_JOURNAL_FLAG_LAST_TAG 8
/* Maximum entries in 1 journal transaction */
#define MAX_JOURNAL_ENTRIES 100
struct journal_log {
char *buf;
int blknr;
};
struct dirty_blocks {
char *buf;
int blknr;
};
/* Standard header for all descriptor blocks: */
struct journal_header_t {
__be32 h_magic;
__be32 h_blocktype;
__be32 h_sequence;
};
/* The journal superblock. All fields are in big-endian byte order. */
struct journal_superblock_t {
/* 0x0000 */
struct journal_header_t s_header;
/* Static information describing the journal */
__be32 s_blocksize; /* journal device blocksize */
__be32 s_maxlen; /* total blocks in journal file */
__be32 s_first; /* first block of log information */
/* Dynamic information describing the current state of the log */
__be32 s_sequence; /* first commit ID expected in log */
__be32 s_start; /* blocknr of start of log */
/* Error value, as set by journal_abort(). */
__be32 s_errno;
/* Remaining fields are only valid in a version-2 superblock */
__be32 s_feature_compat; /* compatible feature set */
__be32 s_feature_incompat; /* incompatible feature set */
__be32 s_feature_ro_compat; /* readonly-compatible feature set */
/* 0x0030 */
__u8 s_uuid[16]; /* 128-bit uuid for journal */
/* 0x0040 */
__be32 s_nr_users; /* Nr of filesystems sharing log */
__be32 s_dynsuper; /* Blocknr of dynamic superblock copy */
/* 0x0048 */
__be32 s_max_transaction; /* Limit of journal blocks per trans. */
__be32 s_max_trans_data; /* Limit of data blocks per trans. */
/* 0x0050 */
__be32 s_padding[44];
/* 0x0100 */
__u8 s_users[16 * 48]; /* ids of all fs'es sharing the log */
/* 0x0400 */
} ;
struct ext3_journal_block_tag {
__be32 block;
__be32 flags;
};
struct journal_revoke_header_t {
struct journal_header_t r_header;
__be32 r_count; /* Count of bytes used in the block */
};
struct revoke_blk_list {
char *content; /* revoke block itself */
struct revoke_blk_list *next;
};
extern struct ext2_data *ext4fs_root;
int ext4fs_init_journal(void);
int ext4fs_log_gdt(char *gd_table);
int ext4fs_check_journal_state(int recovery_flag);
int ext4fs_log_journal(char *journal_buffer, uint32_t blknr);
int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr);
void ext4fs_update_journal(void);
void ext4fs_dump_metadata(void);
void ext4fs_push_revoke_blk(char *buffer);
void ext4fs_free_journal(void);
void ext4fs_free_revoke_blks(void);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2011 - 2012 Samsung Electronics
* EXT4 filesystem implementation in Uboot by
* Uma Shankar <uma.shankar@samsung.com>
* Manjunatha C Achar <a.manjunatha@samsung.com>
*
* ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
* Ext4 read optimization taken from Open-Moko
* Qi bootloader
*
* (C) Copyright 2004
* esd gmbh <www.esd-electronics.com>
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
*
* based on code from grub2 fs/ext2.c and fs/fshelp.c by
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
*
* ext4write : Based on generic ext4 protocol.
*/
#include <common.h>
#include <ext_common.h>
#include <ext4fs.h>
#include "ext4_common.h"
#include <div64.h>
int ext4fs_symlinknest;
struct ext_filesystem ext_fs;
struct ext_filesystem *get_fs(void)
{
return &ext_fs;
}
void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
{
if ((node != &ext4fs_root->diropen) && (node != currroot))
free(node);
}
/*
* Taken from openmoko-kernel mailing list: By Andy green
* Optimized read file API : collects and defers contiguous sector
* reads into one potentially more efficient larger sequential read action
*/
int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
loff_t len, char *buf, loff_t *actread)
{
struct ext_filesystem *fs = get_fs();
int i;
lbaint_t blockcnt;
int log2blksz = fs->dev_desc->log2blksz;
int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
int blocksize = (1 << (log2_fs_blocksize + log2blksz));
unsigned int filesize = le32_to_cpu(node->inode.size);
lbaint_t previous_block_number = -1;
lbaint_t delayed_start = 0;
lbaint_t delayed_extent = 0;
lbaint_t delayed_skipfirst = 0;
lbaint_t delayed_next = 0;
char *delayed_buf = NULL;
char *start_buf = buf;
short status;
struct ext_block_cache cache;
ext_cache_init(&cache);
/* Adjust len so it we can't read past the end of the file. */
if (len + pos > filesize)
len = (filesize - pos);
if (blocksize <= 0 || len <= 0) {
ext_cache_fini(&cache);
return -1;
}
blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
long int blknr;
int blockoff = pos - (blocksize * i);
int blockend = blocksize;
int skipfirst = 0;
blknr = read_allocated_block(&node->inode, i, &cache);
if (blknr < 0) {
ext_cache_fini(&cache);
return -1;
}
blknr = blknr << log2_fs_blocksize;
/* Last block. */
if (i == blockcnt - 1) {
blockend = (len + pos) - (blocksize * i);
/* The last portion is exactly blocksize. */
if (!blockend)
blockend = blocksize;
}
/* First block. */
if (i == lldiv(pos, blocksize)) {
skipfirst = blockoff;
blockend -= skipfirst;
}
if (blknr) {
int status;
if (previous_block_number != -1) {
if (delayed_next == blknr) {
delayed_extent += blockend;
delayed_next += blockend >> log2blksz;
} else { /* spill */
status = ext4fs_devread(delayed_start,
delayed_skipfirst,
delayed_extent,
delayed_buf);
if (status == 0) {
ext_cache_fini(&cache);
return -1;
}
previous_block_number = blknr;
delayed_start = blknr;
delayed_extent = blockend;
delayed_skipfirst = skipfirst;
delayed_buf = buf;
delayed_next = blknr +
(blockend >> log2blksz);
}
} else {
previous_block_number = blknr;
delayed_start = blknr;
delayed_extent = blockend;
delayed_skipfirst = skipfirst;
delayed_buf = buf;
delayed_next = blknr +
(blockend >> log2blksz);
}
} else {
int n;
int n_left;
if (previous_block_number != -1) {
/* spill */
status = ext4fs_devread(delayed_start,
delayed_skipfirst,
delayed_extent,
delayed_buf);
if (status == 0) {
ext_cache_fini(&cache);
return -1;
}
previous_block_number = -1;
}
/* Zero no more than `len' bytes. */
n = blocksize - skipfirst;
n_left = len - ( buf - start_buf );
if (n > n_left)
n = n_left;
memset(buf, 0, n);
}
buf += blocksize - skipfirst;
}
if (previous_block_number != -1) {
/* spill */
status = ext4fs_devread(delayed_start,
delayed_skipfirst, delayed_extent,
delayed_buf);
if (status == 0) {
ext_cache_fini(&cache);
return -1;
}
previous_block_number = -1;
}
*actread = len;
ext_cache_fini(&cache);
return 0;
}
int ext4fs_ls(const char *dirname)
{
struct ext2fs_node *dirnode = NULL;
int status;
if (dirname == NULL)
return 0;
status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
FILETYPE_DIRECTORY);
if (status != 1) {
printf("** Can not find directory. **\n");
if (dirnode)
ext4fs_free_node(dirnode, &ext4fs_root->diropen);
return 1;
}
ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
ext4fs_free_node(dirnode, &ext4fs_root->diropen);
return 0;
}
int ext4fs_exists(const char *filename)
{
loff_t file_len;
int ret;
ret = ext4fs_open(filename, &file_len);
return ret == 0;
}
int ext4fs_size(const char *filename, loff_t *size)
{
return ext4fs_open(filename, size);
}
int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread)
{
if (ext4fs_root == NULL || ext4fs_file == NULL)
return -1;
return ext4fs_read_file(ext4fs_file, offset, len, buf, actread);
}
int ext4fs_probe(struct blk_desc *fs_dev_desc,
disk_partition_t *fs_partition)
{
ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
if (!ext4fs_mount(fs_partition->size)) {
ext4fs_close();
return -1;
}
return 0;
}
int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *len_read)
{
loff_t file_len;
int ret;
ret = ext4fs_open(filename, &file_len);
if (ret < 0) {
printf("** File not found %s **\n", filename);
return -1;
}
if (len == 0)
len = file_len;
return ext4fs_read(buf, offset, len, len_read);
}
int ext4fs_uuid(char *uuid_str)
{
if (ext4fs_root == NULL)
return -1;
#ifdef CONFIG_LIB_UUID
uuid_bin_to_str((unsigned char *)ext4fs_root->sblock.unique_id,
uuid_str, UUID_STR_FORMAT_STD);
return 0;
#else
return -ENOSYS;
#endif
}
void ext_cache_init(struct ext_block_cache *cache)
{
memset(cache, 0, sizeof(*cache));
}
void ext_cache_fini(struct ext_block_cache *cache)
{
free(cache->buf);
ext_cache_init(cache);
}
int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
{
/* This could be more lenient, but this is simple and enough for now */
if (cache->buf && cache->block == block && cache->size == size)
return 1;
ext_cache_fini(cache);
cache->buf = malloc(size);
if (!cache->buf)
return 0;
if (!ext4fs_devread(block, 0, size, cache->buf)) {
ext_cache_fini(cache);
return 0;
}
cache->block = block;
cache->size = size;
return 1;
}