From 9e0daf9bac10e4426efd6f6dd6586ce80cabbe3e Mon Sep 17 00:00:00 2001 From: Judith Mendez Date: Mon, 10 Feb 2025 14:29:42 -0600 Subject: cmd: Enable CMD remoteproc by default for K3 ARCH Enable CMD_REMOTEPROC by default if building for K3 ARCH so that it does not have to be defined in each board defconfig file. Signed-off-by: Judith Mendez --- cmd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'cmd') diff --git a/cmd/Kconfig b/cmd/Kconfig index 4c4ad9d9979..4250bfcaf34 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1587,6 +1587,7 @@ config CMD_READ config CMD_REMOTEPROC bool "remoteproc" depends on REMOTEPROC + default y if ARCH_K3 help Support for Remote Processor control -- cgit v1.3.1 From 06159a1465fc97d8d7b72b9bea39a396f6e7057c Mon Sep 17 00:00:00 2001 From: Gabriel Dalimonte Date: Mon, 17 Feb 2025 13:26:44 -0500 Subject: fs: fat: add rename The implementation roughly follows the POSIX specification for rename() [1]. The ordering of operations attempting to minimize the chance for data loss in unexpected circumstances. The 'mv' command was implemented as a front end for the rename operation as that is what most users are likely familiar with in terms of behavior. The 'FAT_RENAME' Kconfig option was added to prevent code size increase on size-oriented builds like SPL. [1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/rename.html Signed-off-by: Gabriel Dalimonte --- cmd/fs.c | 14 ++ doc/usage/cmd/mv.rst | 61 ++++++ fs/fat/Kconfig | 7 + fs/fat/fat_write.c | 285 ++++++++++++++++++++++++ fs/fs.c | 65 +++++- include/fat.h | 1 + include/fs.h | 2 + lib/efi_loader/Kconfig | 1 + test/py/tests/test_fs/conftest.py | 121 +++++++++++ test/py/tests/test_fs/fstest_helpers.py | 2 + test/py/tests/test_fs/test_rename.py | 372 ++++++++++++++++++++++++++++++++ 11 files changed, 930 insertions(+), 1 deletion(-) create mode 100644 doc/usage/cmd/mv.rst create mode 100644 test/py/tests/test_fs/test_rename.py (limited to 'cmd') diff --git a/cmd/fs.c b/cmd/fs.c index 3d7e06d6f1e..3faf7627447 100644 --- a/cmd/fs.c +++ b/cmd/fs.c @@ -110,3 +110,17 @@ U_BOOT_CMD( fstypes, 1, 1, do_fstypes_wrapper, "List supported filesystem types", "" ); + +static int do_mv_wrapper(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + return do_mv(cmdtp, flag, argc, argv, FS_TYPE_ANY); +} + +U_BOOT_CMD( + mv, 5, 1, do_mv_wrapper, + "rename/move a file/directory", + " [] \n" + " - renames/moves a file/directory in 'dev' on 'interface' from\n" + " 'old_path' to 'new_path'" +); diff --git a/doc/usage/cmd/mv.rst b/doc/usage/cmd/mv.rst new file mode 100644 index 00000000000..99864371038 --- /dev/null +++ b/doc/usage/cmd/mv.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: mv (command) + +mv command +========== + +Synopsis +-------- + +:: + + mv [] + +Description +----------- + +The mv command renames/moves a file or directory within a filesystem. + +interface + interface for accessing the block device (mmc, sata, scsi, usb, ....) + +dev + device number + +part + partition number, defaults to 0 (whole device) + +old_path + existing path to file/directory + +new_path + new path/name for the rename/move + + +Example +------- + + # Rename file 'foo' in directory 'dir' to 'bar' + mv mmc 0:0 dir/foo dir/bar + + # Move file 'f' from directory 'foo' to existing directory 'bar' renaming + # 'f' to 'g' + mv mmc 0:0 foo/f bar/g + + # Move directory 'abc' in directory 'dir1' into existing directory 'dir2' + mv mmc 0:0 dir1/abc dir2 + +Configuration +------------- + +The mv command is only available if CONFIG_CMD_FS_GENERIC=y. + +Return value +------------ + +The return value $? is set to 0 (true) if the file was successfully +renamed/moved. + +If an error occurs, the return value $? is set to 1 (false). diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig index 9bb11eac9f7..19d52238713 100644 --- a/fs/fat/Kconfig +++ b/fs/fat/Kconfig @@ -13,6 +13,13 @@ config FAT_WRITE This provides support for creating and writing new files to an existing FAT filesystem partition. +config FAT_RENAME + bool "Enable filesystem rename support" + depends on FAT_WRITE + help + This provides support for renaming and moving files within a + FAT filesystem partition. + config FS_FAT_MAX_CLUSTSIZE int "Set maximum possible clustersize" default 65536 diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 86366d03853..d4952e259ff 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -1215,6 +1215,28 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr, memcpy(&dentptr->nameext, shortname, SHORT_NAME_SIZE); } +/** + * fat_itr_parent() - modifies the iterator to the parent directory of the + * current iterator. + * + * @itr: iterator positioned anywhere in a directory + * @Return: 0 if the iterator is in the parent directory, -errno otherwise + */ +static int fat_itr_parent(fat_itr *itr) +{ + int ret; + + if (itr->is_root) + return -EIO; + + /* ensure iterator is at the first directory entry */ + ret = fat_move_to_cluster(itr, itr->start_clust); + if (ret) + return ret; + + return fat_itr_resolve(itr, "..", TYPE_DIR); +} + /** * create_link() - inserts a directory entry for a file or directory * @@ -1822,3 +1844,266 @@ exit: free(dotdent); return ret; } + +/** + * check_path_prefix() - ensures one path does not contains another path as a + * prefix. + * + * for example: path foo/bar/baz/qux contains the path prefix foo/bar/baz + * + * note: the iterator may be pointing to any directory entry in the directory + * + * @prefix_clust: start cluster of the final directory in the prefix path + * (the start cluster of 'baz' in the above example) + * @path_itr: iterator of the path to check (an iterator pointing to any + * direntry in 'qux' in the above example) + * Return: -errno on error, 0 if path_itr does not have the directory + * at prefix_clust as an ancestor. + */ +static int check_path_prefix(loff_t prefix_clust, fat_itr *path_itr) +{ + fat_itr itr; + fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata; + int ret; + + /* duplicate fsdata */ + itr = *path_itr; + fsdata = *itr.fsdata; + + /* allocate local fat buffer */ + fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE); + if (!fsdata.fatbuf) { + log_debug("Error: allocating memory\n"); + ret = -ENOMEM; + goto exit; + } + + fsdata.fatbufnum = -1; + itr.fsdata = &fsdata; + + /* ensure iterator is at the first directory entry */ + ret = fat_move_to_cluster(&itr, itr.start_clust); + if (ret) + goto exit; + + while (1) { + if (prefix_clust == itr.start_clust) { + ret = -EINVAL; + goto exit; + } + + if (itr.is_root) { + ret = 0; + goto exit; + } + + /* Should not occur in a well-formed FAT filesystem besides the root */ + if (fat_itr_parent(&itr)) { + log_debug("FAT filesystem corrupt!\n"); + log_debug("dir @ clust %u has no parent direntry\n", + itr.start_clust); + ret = -EIO; + goto exit; + } + } + +exit: + free(fsdata.fatbuf); + return ret; +} + +/** + * fat_rename - rename/move a file or directory + * + * @old_path: path to the existing file/directory + * @new_path: new path/name for the rename/move + * Return: 0 on success, -errno otherwise + */ +int fat_rename(const char *old_path, const char *new_path) +{ + fat_itr *old_itr = NULL, *new_itr = NULL; + fsdata old_datablock = { .fatbuf = NULL, }; + fsdata new_datablock = { .fatbuf = NULL, }; + /* used for START macro */ + fsdata *mydata = &old_datablock; + int ret = -EIO, is_old_dir; + char *old_path_copy, *old_dirname, *old_basename; + char *new_path_copy, *new_dirname, *new_basename; + char l_new_basename[VFAT_MAXLEN_BYTES]; + __u32 old_clust; + dir_entry *found_existing; + /* only set if found_existing != NULL */ + __u32 new_clust; + + old_path_copy = strdup(old_path); + new_path_copy = strdup(new_path); + old_itr = malloc_cache_aligned(sizeof(fat_itr)); + new_itr = malloc_cache_aligned(sizeof(fat_itr)); + if (!old_path_copy || !new_path_copy || !old_itr || !new_itr) { + log_debug("Error: out of memory\n"); + ret = -ENOMEM; + goto exit; + } + split_filename(old_path_copy, &old_dirname, &old_basename); + split_filename(new_path_copy, &new_dirname, &new_basename); + + if (normalize_longname(l_new_basename, new_basename)) { + log_debug("FAT: illegal filename (%s)\n", new_basename); + ret = -EINVAL; + goto exit; + } + + if (!strcmp(old_basename, ".") || !strcmp(old_basename, "..") || + !strcmp(old_basename, "") || !strcmp(l_new_basename, ".") || + !strcmp(l_new_basename, "..") || !strcmp(l_new_basename, "")) { + ret = -EINVAL; + goto exit; + } + + /* checking for old_path == new_path is deferred until they're resolved */ + + /* resolve old_path */ + ret = fat_itr_root(old_itr, &old_datablock); + if (ret) + goto exit; + + ret = fat_itr_resolve(old_itr, old_dirname, TYPE_DIR); + if (ret) { + log_debug("%s doesn't exist (%d)\n", old_dirname, ret); + ret = -ENOENT; + goto exit; + } + + if (!find_directory_entry(old_itr, old_basename)) { + log_debug("%s doesn't exist (%d)\n", old_basename, -ENOENT); + ret = -ENOENT; + goto exit; + } + + /* store clust old_path points to, to relink later */ + total_sector = old_datablock.total_sect; + old_clust = START(old_itr->dent); + is_old_dir = fat_itr_isdir(old_itr); + + /* resolve new_path*/ + ret = fat_itr_root(new_itr, &new_datablock); + if (ret) + goto exit; + + ret = fat_itr_resolve(new_itr, new_dirname, TYPE_DIR); + if (ret) { + log_debug("%s doesn't exist (%d)\n", new_dirname, ret); + ret = -ENOENT; + goto exit; + } + + found_existing = find_directory_entry(new_itr, l_new_basename); + + if (found_existing) { + /* store cluster of new_path since it may need to be deleted */ + new_clust = START(new_itr->dent); + + /* old_path is new_path, noop */ + if (old_clust == new_clust) { + ret = 0; + goto exit; + } + + if (fat_itr_isdir(new_itr) != is_old_dir) { + if (is_old_dir) + ret = -ENOTDIR; + else + ret = -EISDIR; + goto exit; + } + } + + if (is_old_dir) { + ret = check_path_prefix(old_clust, new_itr); + if (ret) + goto exit; + } + + /* create/update dentry to point to old_path's data cluster */ + if (found_existing) { + struct nameext new_name = new_itr->dent->nameext; + __u8 lcase = new_itr->dent->lcase; + + if (is_old_dir) { + int n_entries = fat_dir_entries(new_itr); + + if (n_entries < 0) { + ret = n_entries; + goto exit; + } + if (n_entries > 2) { + log_debug("Error: directory is not empty: %d\n", + n_entries); + ret = -ENOTEMPTY; + goto exit; + } + } + + *new_itr->dent = *old_itr->dent; + new_itr->dent->nameext = new_name; + new_itr->dent->lcase = lcase; + } else { + /* reset iterator to the start of the directory */ + ret = fat_move_to_cluster(new_itr, new_itr->start_clust); + if (ret) + goto exit; + + ret = create_link(new_itr, l_new_basename, old_clust, + old_itr->dent->size, + old_itr->dent->attr | ATTR_ARCH); + if (ret) + goto exit; + } + + ret = flush_dir(new_itr); + if (ret) + goto exit; + + /* with new_path data cluster unreferenced, clear it */ + if (found_existing) { + ret = clear_fatent(&new_datablock, new_clust); + if (ret) + goto exit; + } + + /* update moved directory so the parent is new_path */ + if (is_old_dir) { + __u32 clust = new_itr->start_clust; + dir_entry *dent; + + fat_itr_child(new_itr, new_itr); + dent = find_directory_entry(new_itr, ".."); + if (!dent) { + log_debug("FAT filesystem corrupt!\n"); + log_debug("dir %s has no parent direntry\n", + l_new_basename); + ret = -EIO; + goto exit; + } + set_start_cluster(&new_datablock, dent, clust); + ret = flush_dir(new_itr); + if (ret) + goto exit; + } + + /* refresh old in case write happened to the same block. */ + ret = fat_move_to_cluster(old_itr, old_itr->dent_clust); + if (ret) + goto exit; + + ret = delete_dentry_link(old_itr); +exit: + free(new_datablock.fatbuf); + free(old_datablock.fatbuf); + free(new_itr); + free(old_itr); + free(new_path_copy); + free(old_path_copy); + + return ret; +} diff --git a/fs/fs.c b/fs/fs.c index fdff83719b1..30a8e5010f2 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -213,12 +213,16 @@ static struct fstype_info fstypes[] = { .unlink = fs_unlink_unsupported, .mkdir = fs_mkdir_unsupported, #endif - .rename = fs_rename_unsupported, .uuid = fat_uuid, .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, .ln = fs_ln_unsupported, +#if CONFIG_IS_ENABLED(FAT_RENAME) && !IS_ENABLED(CONFIG_XPL_BUILD) + .rename = fat_rename, +#else + .rename = fs_rename_unsupported, +#endif }, #endif @@ -1007,6 +1011,65 @@ int do_ln(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], return 0; } +int do_mv(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], + int fstype) +{ + struct fs_dir_stream *dirs; + char *src = argv[3]; + char *dst = argv[4]; + char *new_dst = NULL; + int ret = 1; + + if (argc != 5) { + ret = CMD_RET_USAGE; + goto exit; + } + + if (fs_set_blk_dev(argv[1], argv[2], fstype)) + goto exit; + + dirs = fs_opendir(dst); + /* dirs being valid means dst points to an existing directory. + * mv should copy the file/dir (keeping the same name) into the + * directory + */ + if (dirs) { + char *src_name = strrchr(src, '/'); + int dst_len; + + if (src_name) + src_name += 1; + else + src_name = src; + + dst_len = strlen(dst); + new_dst = calloc(1, dst_len + strlen(src_name) + 2); + strcpy(new_dst, dst); + + /* If there is already a trailing slash, don't add another */ + if (new_dst[dst_len - 1] != '/') { + new_dst[dst_len] = '/'; + dst_len += 1; + } + + strcpy(new_dst + dst_len, src_name); + dst = new_dst; + } + fs_closedir(dirs); + + if (fs_set_blk_dev(argv[1], argv[2], fstype)) + goto exit; + + if (fs_rename(src, dst)) + goto exit; + + ret = 0; + +exit: + free(new_dst); + return ret; +} + int do_fs_types(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { struct fstype_info *drv = fstypes; diff --git a/include/fat.h b/include/fat.h index 3dce99a23cf..ca97880de12 100644 --- a/include/fat.h +++ b/include/fat.h @@ -206,6 +206,7 @@ int fat_opendir(const char *filename, struct fs_dir_stream **dirsp); int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp); void fat_closedir(struct fs_dir_stream *dirs); int fat_unlink(const char *filename); +int fat_rename(const char *old_path, const char *new_path); int fat_mkdir(const char *dirname); void fat_close(void); void *fat_next_cluster(fat_itr *itr, unsigned int *nbytes); diff --git a/include/fs.h b/include/fs.h index 5b272eb9f5e..54449faf2e5 100644 --- a/include/fs.h +++ b/include/fs.h @@ -302,6 +302,8 @@ int do_mkdir(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], int fstype); int do_ln(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], int fstype); +int do_mv(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], + int fstype); /* * Determine the UUID of the specified filesystem and print it. Optionally it is diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index d4f6b56afaa..6130af14337 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -27,6 +27,7 @@ config EFI_LOADER select REGEX imply FAT imply FAT_WRITE + imply FAT_RENAME imply USB_KEYBOARD_FN_KEYS imply VIDEO_ANSI help diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py index af2adaf1645..7bfcf41ed6f 100644 --- a/test/py/tests/test_fs/conftest.py +++ b/test/py/tests/test_fs/conftest.py @@ -18,6 +18,7 @@ supported_fs_fat = ['fat12', 'fat16'] supported_fs_mkdir = ['fat12', 'fat16', 'fat32'] supported_fs_unlink = ['fat12', 'fat16', 'fat32'] supported_fs_symlink = ['ext4'] +supported_fs_rename = ['fat12', 'fat16', 'fat32'] # # Filesystem test specific setup @@ -55,6 +56,7 @@ def pytest_configure(config): global supported_fs_mkdir global supported_fs_unlink global supported_fs_symlink + global supported_fs_rename def intersect(listA, listB): return [x for x in listA if x in listB] @@ -68,6 +70,7 @@ def pytest_configure(config): supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir) supported_fs_unlink = intersect(supported_fs, supported_fs_unlink) supported_fs_symlink = intersect(supported_fs, supported_fs_symlink) + supported_fs_rename = intersect(supported_fs, supported_fs_rename) def pytest_generate_tests(metafunc): """Parametrize fixtures, fs_obj_xxx @@ -99,6 +102,9 @@ def pytest_generate_tests(metafunc): if 'fs_obj_symlink' in metafunc.fixturenames: metafunc.parametrize('fs_obj_symlink', supported_fs_symlink, indirect=True, scope='module') + if 'fs_obj_rename' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_rename', supported_fs_rename, + indirect=True, scope='module') # # Helper functions @@ -527,6 +533,121 @@ def fs_obj_symlink(request, u_boot_config): call('rm -rf %s' % scratch_dir, shell=True) call('rm -f %s' % fs_img, shell=True) +# +# Fixture for rename test +# +@pytest.fixture() +def fs_obj_rename(request, u_boot_config): + """Set up a file system to be used in rename tests. + + Args: + request: Pytest request object. + u_boot_config: U-Boot configuration. + + Return: + A fixture for rename tests, i.e. a triplet of file system type, + volume file name, and dictionary of test identifier and md5val. + """ + def new_rand_file(path): + check_call('dd if=/dev/urandom of=%s bs=1K count=1' % path, shell=True) + + def file_hash(path): + out = check_output( + 'dd if=%s bs=1K skip=0 count=1 2> /dev/null | md5sum' % path, + shell=True + ) + return out.decode().split()[0] + + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + mount_dir = u_boot_config.persistent_data_dir + '/scratch' + + try: + check_call('mkdir -p %s' % mount_dir, shell=True) + except CalledProcessError as err: + pytest.skip('Preparing mount folder failed for filesystem: ' + fs_type + '. {}'.format(err)) + call('rm -f %s' % fs_img, shell=True) + return + + try: + md5val = {} + # Test Case 1 + check_call('mkdir %s/test1' % mount_dir, shell=True) + new_rand_file('%s/test1/file1' % mount_dir) + md5val['test1'] = file_hash('%s/test1/file1' % mount_dir) + + # Test Case 2 + check_call('mkdir %s/test2' % mount_dir, shell=True) + new_rand_file('%s/test2/file1' % mount_dir) + new_rand_file('%s/test2/file_exist' % mount_dir) + md5val['test2'] = file_hash('%s/test2/file1' % mount_dir) + + # Test Case 3 + check_call('mkdir -p %s/test3/dir1' % mount_dir, shell=True) + new_rand_file('%s/test3/dir1/file1' % mount_dir) + md5val['test3'] = file_hash('%s/test3/dir1/file1' % mount_dir) + + # Test Case 4 + check_call('mkdir -p %s/test4/dir1' % mount_dir, shell=True) + check_call('mkdir -p %s/test4/dir2/dir1' % mount_dir, shell=True) + new_rand_file('%s/test4/dir1/file1' % mount_dir) + md5val['test4'] = file_hash('%s/test4/dir1/file1' % mount_dir) + + # Test Case 5 + check_call('mkdir -p %s/test5/dir1' % mount_dir, shell=True) + new_rand_file('%s/test5/file2' % mount_dir) + md5val['test5'] = file_hash('%s/test5/file2' % mount_dir) + + # Test Case 6 + check_call('mkdir -p %s/test6/dir2/existing' % mount_dir, shell=True) + new_rand_file('%s/test6/existing' % mount_dir) + md5val['test6'] = file_hash('%s/test6/existing' % mount_dir) + + # Test Case 7 + check_call('mkdir -p %s/test7/dir1' % mount_dir, shell=True) + check_call('mkdir -p %s/test7/dir2/dir1' % mount_dir, shell=True) + new_rand_file('%s/test7/dir2/dir1/file1' % mount_dir) + md5val['test7'] = file_hash('%s/test7/dir2/dir1/file1' % mount_dir) + + # Test Case 8 + check_call('mkdir -p %s/test8/dir1' % mount_dir, shell=True) + new_rand_file('%s/test8/dir1/file1' % mount_dir) + md5val['test8'] = file_hash('%s/test8/dir1/file1' % mount_dir) + + # Test Case 9 + check_call('mkdir -p %s/test9/dir1/nested/inner' % mount_dir, shell=True) + new_rand_file('%s/test9/dir1/nested/inner/file1' % mount_dir) + + # Test Case 10 + check_call('mkdir -p %s/test10' % mount_dir, shell=True) + new_rand_file('%s/test10/file1' % mount_dir) + md5val['test10'] = file_hash('%s/test10/file1' % mount_dir) + + # Test Case 11 + check_call('mkdir -p %s/test11/dir1' % mount_dir, shell=True) + new_rand_file('%s/test11/dir1/file1' % mount_dir) + md5val['test11'] = file_hash('%s/test11/dir1/file1' % mount_dir) + + try: + # 128MiB volume + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, 0x8000000, '128MB', mount_dir) + except CalledProcessError as err: + pytest.skip('Creating failed for filesystem: ' + fs_type + '. {}'.format(err)) + return + + except CalledProcessError: + pytest.skip('Setup failed for filesystem: ' + fs_type) + return + else: + yield [fs_ubtype, fs_img, md5val] + finally: + call('rm -rf %s' % mount_dir, shell=True) + call('rm -f %s' % fs_img, shell=True) + # # Fixture for fat test # diff --git a/test/py/tests/test_fs/fstest_helpers.py b/test/py/tests/test_fs/fstest_helpers.py index faec2982489..c1447b4d43e 100644 --- a/test/py/tests/test_fs/fstest_helpers.py +++ b/test/py/tests/test_fs/fstest_helpers.py @@ -9,5 +9,7 @@ def assert_fs_integrity(fs_type, fs_img): try: if fs_type == 'ext4': check_call('fsck.ext4 -n -f %s' % fs_img, shell=True) + elif fs_type in ['fat12', 'fat16', 'fat32']: + check_call('fsck.fat -n %s' % fs_img, shell=True) except CalledProcessError: raise diff --git a/test/py/tests/test_fs/test_rename.py b/test/py/tests/test_fs/test_rename.py new file mode 100644 index 00000000000..df2b2fd2945 --- /dev/null +++ b/test/py/tests/test_fs/test_rename.py @@ -0,0 +1,372 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2025 Gabriel Dalimonte +# +# U-Boot File System:rename Test + + +import pytest + +from fstest_defs import * +from fstest_helpers import assert_fs_integrity + +@pytest.mark.boardspec('sandbox') +@pytest.mark.slow +class TestRename(object): + def test_rename1(self, u_boot_console, fs_obj_rename): + """ + Test Case 1 - rename a file (successful mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 1 - rename a file'): + d = 'test1' + src = '%s/file1' % d + dst = '%s/file2' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s' % (ADDR, dst), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('file1' not in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test1'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename2(self, u_boot_console, fs_obj_rename): + """ + Test Case 2 - rename a file to an existing file (successful mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 2 - rename a file to an existing file'): + d = 'test2' + src = '%s/file1' % d + dst = '%s/file_exist' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s' % (ADDR, dst), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('file1' not in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test2'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename3(self, u_boot_console, fs_obj_rename): + """ + Test Case 3 - rename a directory (successful mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 3 - rename a directory'): + d = 'test3' + src = '%s/dir1' % d + dst = '%s/dir2' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s/file1' % (ADDR, dst), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir1' not in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test3'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename4(self, u_boot_console, fs_obj_rename): + """ + Test Case 4 - rename a directory to an existing directory (successful + mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 4 - rename a directory to an existing directory'): + d = 'test4' + src = '%s/dir1' % d + dst = '%s/dir2' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s/dir1/file1' % (ADDR, dst), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir1' not in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test4'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename5(self, u_boot_console, fs_obj_rename): + """ + Test Case 5 - rename a directory to an existing file (failed mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 5 - rename a directory to an existing file'): + d = 'test5' + src = '%s/dir1' % d + dst = '%s/file2' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir1' in ''.join(output)) + assert('file2' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s' % (ADDR, dst), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test5'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename6(self, u_boot_console, fs_obj_rename): + """ + Test Case 6 - rename a file to an existing empty directory (failed mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 6 - rename a file to an existing empty directory'): + d = 'test6' + src = '%s/existing' % d + dst = '%s/dir2' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s' % (ADDR, src), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir2' in ''.join(output)) + assert('existing' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test6'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename7(self, u_boot_console, fs_obj_rename): + """ + Test Case 7 - rename a directory to a non-empty directory (failed mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 7 - rename a directory to a non-empty directory'): + d = 'test7' + src = '%s/dir1' % d + dst = '%s/dir2' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s/dir1/file1' % (ADDR, dst), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir1' in ''.join(output)) + assert('dir2' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test7'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename8(self, u_boot_console, fs_obj_rename): + """ + Test Case 8 - rename a directory inside itself (failed mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 8 - rename a directory inside itself'): + d = 'test8' + src = '%s/dir1' % d + dst = '%s/dir1/dir1' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s/file1' % (ADDR, src), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir1' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (src), + ]) + assert('file1' in ''.join(output)) + assert('dir1' not in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test8'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename9(self, u_boot_console, fs_obj_rename): + """ + Test Case 9 - rename a directory inside itself with backtracks (failed + mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 9 - rename a directory inside itself with backtracks'): + d = 'test9' + src = '%s/dir1/nested' % d + dst = '%s/dir1/nested/inner/./../../../dir1/nested/inner/another' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, dst), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s/dir1' % (d), + ]) + assert('nested' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (src), + ]) + assert('inner' in ''.join(output)) + assert('nested' not in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename10(self, u_boot_console, fs_obj_rename): + """ + Test Case 10 - rename a file to itself (successful mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 10 - rename a file to itself'): + d = 'test10' + src = '%s/file1' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, src), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s' % (ADDR, src), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('file1' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test10'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) + + def test_rename11(self, u_boot_console, fs_obj_rename): + """ + Test Case 11 - rename a directory to itself (successful mv) + """ + fs_type, fs_img, md5val = fs_obj_rename + with u_boot_console.log.section('Test Case 11 - rename a directory to itself'): + # / at the end here is intentional. Ensures trailing / doesn't + # affect mv producing an updated dst path for fs_rename + d = 'test11/' + src = '%sdir1' % d + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'setenv filesize', + 'mv host 0:0 %s %s' % (src, d), + ]) + assert('' == ''.join(output)) + + output = u_boot_console.run_command_list([ + 'load host 0:0 %x /%s/file1' % (ADDR, src), + 'printenv filesize']) + assert('filesize=400' in output) + + output = u_boot_console.run_command_list([ + 'ls host 0:0 %s' % (d), + ]) + assert('dir1' in ''.join(output)) + + output = u_boot_console.run_command_list([ + 'md5sum %x $filesize' % ADDR, + 'setenv filesize']) + assert(md5val['test11'] in ''.join(output)) + assert_fs_integrity(fs_type, fs_img) -- cgit v1.3.1 From 2df965d385872b2ae49a79c2cab4679a8999467f Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Wed, 5 Mar 2025 15:26:42 +0100 Subject: net: lwip: extend wget to support CA (root) certificates Add the "cacert" (Certification Authority certificates) subcommand to wget to pass root certificates to the code handling the HTTPS protocol. The subcommand is enabled by the WGET_CACERT Kconfig symbol. Usage example: => dhcp # Download some root certificates (note: not authenticated!) => wget https://cacerts.digicert.com/DigiCertTLSECCP384RootG5.crt # Provide root certificates => wget cacert $fileaddr $filesize # Enforce verification (it is optional by default) => wget cacert required # Forget the root certificates => wget cacert 0 0 # Disable verification => wget cacert none Signed-off-by: Jerome Forissier Reviewed-by: Ilias Apalodimas --- cmd/Kconfig | 8 +++++ cmd/net-lwip.c | 17 ++++++++-- net/lwip/wget.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 121 insertions(+), 6 deletions(-) (limited to 'cmd') diff --git a/cmd/Kconfig b/cmd/Kconfig index bfed141914a..764de482890 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2176,6 +2176,14 @@ config WGET_HTTPS help Enable TLS over http for wget. +config WGET_CACERT + bool "wget cacert" + depends on CMD_WGET + depends on WGET_HTTPS + help + Adds the "cacert" sub-command to wget to provide root certificates + to the HTTPS engine. Must be in DER format. + endif # if CMD_NET config CMD_PXE diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c index 0fd446ecb20..1152c94a6dc 100644 --- a/cmd/net-lwip.c +++ b/cmd/net-lwip.c @@ -27,9 +27,20 @@ U_BOOT_CMD(dns, 3, 1, do_dns, "lookup the IP of a hostname", #endif #if defined(CONFIG_CMD_WGET) -U_BOOT_CMD(wget, 3, 1, do_wget, - "boot image via network using HTTP/HTTPS protocol", +U_BOOT_CMD(wget, 4, 1, do_wget, + "boot image via network using HTTP/HTTPS protocol" +#if defined(CONFIG_WGET_CACERT) + "\nwget cacert - configure wget root certificates" +#endif + , "[loadAddress] url\n" - "wget [loadAddress] [host:]path" + "wget [loadAddress] [host:]path\n" + " - load file" +#if defined(CONFIG_WGET_CACERT) + "\nwget cacert
\n" + " - provide CA certificates (0 0 to remove current)" + "\nwget cacert none|optional|required\n" + " - set server certificate verification mode (default: optional)" +#endif ); #endif diff --git a/net/lwip/wget.c b/net/lwip/wget.c index 14f27d42998..c22843ee10d 100644 --- a/net/lwip/wget.c +++ b/net/lwip/wget.c @@ -285,9 +285,68 @@ static err_t httpc_headers_done_cb(httpc_state_t *connection, void *arg, struct return ERR_OK; } +#if CONFIG_IS_ENABLED(WGET_HTTPS) +enum auth_mode { + AUTH_NONE, + AUTH_OPTIONAL, + AUTH_REQUIRED, +}; + +static char *cacert; +static size_t cacert_size; +static enum auth_mode cacert_auth_mode = AUTH_OPTIONAL; +#endif + +#if CONFIG_IS_ENABLED(WGET_CACERT) +static int set_auth(enum auth_mode auth) +{ + cacert_auth_mode = auth; + + return CMD_RET_SUCCESS; +} + +static int set_cacert(char * const saddr, char * const ssz) +{ + mbedtls_x509_crt crt; + ulong addr, sz; + int ret; + + if (cacert) + free(cacert); + + addr = hextoul(saddr, NULL); + sz = hextoul(ssz, NULL); + + if (!addr) { + cacert = NULL; + cacert_size = 0; + return CMD_RET_SUCCESS; + } + + cacert = malloc(sz); + if (!cacert) + return CMD_RET_FAILURE; + cacert_size = sz; + + memcpy(cacert, (void *)addr, sz); + + mbedtls_x509_crt_init(&crt); + ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size); + if (ret) { + printf("Could not parse certificates (%d)\n", ret); + free(cacert); + cacert = NULL; + cacert_size = 0; + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} +#endif + static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) { -#if defined CONFIG_WGET_HTTPS +#if CONFIG_IS_ENABLED(WGET_HTTPS) altcp_allocator_t tls_allocator; #endif httpc_connection_t conn; @@ -312,11 +371,34 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) return -1; memset(&conn, 0, sizeof(conn)); -#if defined CONFIG_WGET_HTTPS +#if CONFIG_IS_ENABLED(WGET_HTTPS) if (is_https) { + char *ca = cacert; + size_t ca_sz = cacert_size; + + if (cacert_auth_mode == AUTH_REQUIRED) { + if (!ca || !ca_sz) { + printf("Error: cacert authentication mode is " + "'required' but no CA certificates " + "given\n"); + return CMD_RET_FAILURE; + } + } else if (cacert_auth_mode == AUTH_NONE) { + ca = NULL; + ca_sz = 0; + } else if (cacert_auth_mode == AUTH_OPTIONAL) { + /* + * Nothing to do, this is the default behavior of + * altcp_tls to check server certificates against CA + * certificates when the latter are provided and proceed + * with no verification if not. + */ + } + tls_allocator.alloc = &altcp_tls_alloc; tls_allocator.arg = - altcp_tls_create_config_client(NULL, 0, ctx.server_name); + altcp_tls_create_config_client(ca, ca_sz, + ctx.server_name); if (!tls_allocator.arg) { log_err("error: Cannot create a TLS connection\n"); @@ -369,6 +451,20 @@ int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) ulong dst_addr; char nurl[1024]; +#if CONFIG_IS_ENABLED(WGET_CACERT) + if (argc == 4 && !strncmp(argv[1], "cacert", strlen("cacert"))) + return set_cacert(argv[2], argv[3]); + if (argc == 3 && !strncmp(argv[1], "cacert", strlen("cacert"))) { + if (!strncmp(argv[2], "none", strlen("none"))) + return set_auth(AUTH_NONE); + if (!strncmp(argv[2], "optional", strlen("optional"))) + return set_auth(AUTH_OPTIONAL); + if (!strncmp(argv[2], "required", strlen("required"))) + return set_auth(AUTH_REQUIRED); + return CMD_RET_USAGE; + } +#endif + if (argc < 2 || argc > 3) return CMD_RET_USAGE; -- cgit v1.3.1 From 12cc6531a1b2384e6f7d05a7245071536d77e730 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Wed, 5 Mar 2025 15:26:45 +0100 Subject: net: lwip: add support for built-in root certificates Introduce Kconfig symbols WGET_BUILTIN_CACERT and WGET_BUILTIN_CACERT_PATH to provide root certificates at build time. Usage example: wget -O cacert.crt https://cacerts.digicert.com/DigiCertTLSECCP384RootG5.crt make qemu_arm64_lwip_defconfig echo CONFIG_WGET_BUILTIN_CACERT=y >>.config echo CONFIG_WGET_BUILTIN_CACERT_PATH=cacert.crt >>.config make olddefconfig make -j$(nproc) CROSS_COMPILE="ccache aarch64-linux-gnu-" qemu-system-aarch64 -M virt -nographic -cpu max \ -object rng-random,id=rng0,filename=/dev/urandom \ -device virtio-rng-pci,rng=rng0 -bios u-boot.bin => dhcp # HTTPS transfer using the builtin CA certificates => wget https://digicert-tls-ecc-p384-root-g5.chain-demos.digicert.com/ 1867 bytes transferred in 1 ms (1.8 MiB/s) Bytes transferred = 1867 (74b hex) Signed-off-by: Jerome Forissier Reviewed-by: Ilias Apalodimas --- cmd/Kconfig | 14 ++++++++++++++ cmd/net-lwip.c | 4 ++++ net/lwip/Makefile | 6 ++++++ net/lwip/wget.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 72 insertions(+), 9 deletions(-) (limited to 'cmd') diff --git a/cmd/Kconfig b/cmd/Kconfig index 764de482890..cd391d422ae 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2184,6 +2184,20 @@ config WGET_CACERT Adds the "cacert" sub-command to wget to provide root certificates to the HTTPS engine. Must be in DER format. +config WGET_BUILTIN_CACERT + bool "Built-in CA certificates" + depends on WGET_HTTPS + select BUILD_BIN2C + +config WGET_BUILTIN_CACERT_PATH + string "Path to root certificates" + depends on WGET_BUILTIN_CACERT + default "cacert.crt" + help + Set this to the path to a DER-encoded X509 file containing + Certification Authority certificates, a.k.a. root certificates, for + the purpose of authenticating HTTPS connections. + endif # if CMD_NET config CMD_PXE diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c index 1152c94a6dc..58c10fbec7d 100644 --- a/cmd/net-lwip.c +++ b/cmd/net-lwip.c @@ -41,6 +41,10 @@ U_BOOT_CMD(wget, 4, 1, do_wget, " - provide CA certificates (0 0 to remove current)" "\nwget cacert none|optional|required\n" " - set server certificate verification mode (default: optional)" +#if defined(CONFIG_WGET_BUILTIN_CACERT) + "\nwget cacert builtin\n" + " - use the builtin CA certificates" +#endif #endif ); #endif diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 79dd6b3fb50..950c5316bb9 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -6,3 +6,9 @@ obj-$(CONFIG_CMD_DNS) += dns.o obj-$(CONFIG_CMD_PING) += ping.o obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o obj-$(CONFIG_WGET) += wget.o + +ifeq (y,$(CONFIG_WGET_BUILTIN_CACERT)) +$(obj)/builtin_cacert.c: $(CONFIG_WGET_BUILTIN_CACERT_PATH:"%"=%) FORCE + $(call if_changed,bin2c,builtin_cacert) +obj-y += builtin_cacert.o +endif diff --git a/net/lwip/wget.c b/net/lwip/wget.c index c22843ee10d..ec098148835 100644 --- a/net/lwip/wget.c +++ b/net/lwip/wget.c @@ -304,28 +304,34 @@ static int set_auth(enum auth_mode auth) return CMD_RET_SUCCESS; } +#endif -static int set_cacert(char * const saddr, char * const ssz) +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) +extern const char builtin_cacert[]; +extern const size_t builtin_cacert_size; +static bool cacert_initialized; +#endif + +#if CONFIG_IS_ENABLED(WGET_CACERT) || CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) +static int _set_cacert(const void *addr, size_t sz) { mbedtls_x509_crt crt; - ulong addr, sz; + void *p; int ret; if (cacert) free(cacert); - addr = hextoul(saddr, NULL); - sz = hextoul(ssz, NULL); - if (!addr) { cacert = NULL; cacert_size = 0; return CMD_RET_SUCCESS; } - cacert = malloc(sz); - if (!cacert) + p = malloc(sz); + if (!p) return CMD_RET_FAILURE; + cacert = p; cacert_size = sz; memcpy(cacert, (void *)addr, sz); @@ -340,9 +346,31 @@ static int set_cacert(char * const saddr, char * const ssz) return CMD_RET_FAILURE; } +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) + cacert_initialized = true; +#endif return CMD_RET_SUCCESS; } + +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) +static int set_cacert_builtin(void) +{ + return _set_cacert(builtin_cacert, builtin_cacert_size); +} +#endif + +#if CONFIG_IS_ENABLED(WGET_CACERT) +static int set_cacert(char * const saddr, char * const ssz) +{ + ulong addr, sz; + + addr = hextoul(saddr, NULL); + sz = hextoul(ssz, NULL); + + return _set_cacert((void *)addr, sz); +} #endif +#endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) { @@ -373,8 +401,15 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) memset(&conn, 0, sizeof(conn)); #if CONFIG_IS_ENABLED(WGET_HTTPS) if (is_https) { - char *ca = cacert; - size_t ca_sz = cacert_size; + char *ca; + size_t ca_sz; + +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) + if (!cacert_initialized) + set_cacert_builtin(); +#endif + ca = cacert; + ca_sz = cacert_size; if (cacert_auth_mode == AUTH_REQUIRED) { if (!ca || !ca_sz) { @@ -455,6 +490,10 @@ int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) if (argc == 4 && !strncmp(argv[1], "cacert", strlen("cacert"))) return set_cacert(argv[2], argv[3]); if (argc == 3 && !strncmp(argv[1], "cacert", strlen("cacert"))) { +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) + if (!strncmp(argv[2], "builtin", strlen("builtin"))) + return set_cacert_builtin(); +#endif if (!strncmp(argv[2], "none", strlen("none"))) return set_auth(AUTH_NONE); if (!strncmp(argv[2], "optional", strlen("optional"))) -- cgit v1.3.1 From 6fd111bc4e84e039f1f59592693710703e991848 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 27 Feb 2025 14:50:48 -0600 Subject: cmd: Drop last reference to CMD_REISERFS While the code was removed in commit 3766a249a3c0 ("fs: drop reiserfs") this reference in the Makefile was missed. Remove it now. Fixes: 3766a249a3c0 ("fs: drop reiserfs") Reviewed-by: Peter Robinson Signed-off-by: Tom Rini --- cmd/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'cmd') diff --git a/cmd/Makefile b/cmd/Makefile index 8410be576bb..c1275d466c8 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -155,7 +155,6 @@ obj-$(CONFIG_CMD_QFW) += qfw.o obj-$(CONFIG_CMD_READ) += read.o obj-$(CONFIG_CMD_WRITE) += read.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o -obj-$(CONFIG_CMD_REISER) += reiser.o obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o obj-$(CONFIG_CMD_RNG) += rng.o obj-$(CONFIG_CMD_KASLRSEED) += kaslrseed.o -- cgit v1.3.1 From e34ecf9d5ef15590c4681c651d508097ebf2b026 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 20 Feb 2025 15:54:38 +0200 Subject: meminfo: add memory details for armv8 Upcoming patches are mapping memory with RO, RW^X etc permsissions. Fix the meminfo command to display them properly Acked-by: Jerome Forissier Reviewed-by: Caleb Connolly Signed-off-by: Ilias Apalodimas --- arch/arm/cpu/armv8/cache_v8.c | 26 +++++++++++++++++++++++--- arch/arm/include/asm/armv8/mmu.h | 2 ++ cmd/meminfo.c | 6 ++++++ 3 files changed, 31 insertions(+), 3 deletions(-) (limited to 'cmd') diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c index 5d6953ffedd..c4b3da4a8da 100644 --- a/arch/arm/cpu/armv8/cache_v8.c +++ b/arch/arm/cpu/armv8/cache_v8.c @@ -421,7 +421,7 @@ static int count_ranges(void) return count; } -#define ALL_ATTRS (3 << 8 | PMD_ATTRINDX_MASK) +#define ALL_ATTRS (3 << 8 | PMD_ATTRMASK) #define PTE_IS_TABLE(pte, level) (pte_type(&(pte)) == PTE_TYPE_TABLE && (level) < 3) enum walker_state { @@ -568,6 +568,20 @@ static void pretty_print_table_attrs(u64 pte) static void pretty_print_block_attrs(u64 pte) { u64 attrs = pte & PMD_ATTRINDX_MASK; + u64 perm_attrs = pte & PMD_ATTRMASK; + char mem_attrs[16] = { 0 }; + int cnt = 0; + + if (perm_attrs & PTE_BLOCK_PXN) + cnt += snprintf(mem_attrs + cnt, sizeof(mem_attrs) - cnt, "PXN "); + if (perm_attrs & PTE_BLOCK_UXN) + cnt += snprintf(mem_attrs + cnt, sizeof(mem_attrs) - cnt, "UXN "); + if (perm_attrs & PTE_BLOCK_RO) + cnt += snprintf(mem_attrs + cnt, sizeof(mem_attrs) - cnt, "RO"); + if (!mem_attrs[0]) + snprintf(mem_attrs, sizeof(mem_attrs), "RWX "); + + printf(" | %-10s", mem_attrs); switch (attrs) { case PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE): @@ -613,6 +627,7 @@ static void print_pte(u64 pte, int level) { if (PTE_IS_TABLE(pte, level)) { printf(" %-5s", "Table"); + printf(" %-12s", "|"); pretty_print_table_attrs(pte); } else { pretty_print_pte_type(pte); @@ -642,9 +657,9 @@ static bool pagetable_print_entry(u64 start_attrs, u64 end, int va_bits, int lev printf("%*s", indent * 2, ""); if (PTE_IS_TABLE(start_attrs, level)) - printf("[%#011llx]%14s", _addr, ""); + printf("[%#016llx]%19s", _addr, ""); else - printf("[%#011llx - %#011llx]", _addr, end); + printf("[%#016llx - %#016llx]", _addr, end); printf("%*s | ", (3 - level) * 2, ""); print_pte(start_attrs, level); @@ -1112,3 +1127,8 @@ void __weak enable_caches(void) icache_enable(); dcache_enable(); } + +void arch_dump_mem_attrs(void) +{ + dump_pagetable(gd->arch.tlb_addr, get_tcr(NULL, NULL)); +} diff --git a/arch/arm/include/asm/armv8/mmu.h b/arch/arm/include/asm/armv8/mmu.h index 0ab681c893d..6af8cd111a4 100644 --- a/arch/arm/include/asm/armv8/mmu.h +++ b/arch/arm/include/asm/armv8/mmu.h @@ -66,6 +66,7 @@ #define PTE_BLOCK_NG (1 << 11) #define PTE_BLOCK_PXN (UL(1) << 53) #define PTE_BLOCK_UXN (UL(1) << 54) +#define PTE_BLOCK_RO (UL(1) << 7) /* * AttrIndx[2:0] @@ -75,6 +76,7 @@ #define PMD_ATTRMASK (PTE_BLOCK_PXN | \ PTE_BLOCK_UXN | \ PMD_ATTRINDX_MASK | \ + PTE_BLOCK_RO | \ PTE_TYPE_VALID) /* diff --git a/cmd/meminfo.c b/cmd/meminfo.c index 5e83d61c2dd..acdb38dcba0 100644 --- a/cmd/meminfo.c +++ b/cmd/meminfo.c @@ -15,6 +15,10 @@ DECLARE_GLOBAL_DATA_PTR; +void __weak arch_dump_mem_attrs(void) +{ +} + static void print_region(const char *name, ulong base, ulong size, ulong *uptop) { ulong end = base + size; @@ -58,6 +62,8 @@ static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc, if (!IS_ENABLED(CONFIG_CMD_MEMINFO_MAP)) return 0; + arch_dump_mem_attrs(); + printf("\n%-12s %8s %8s %8s %8s\n", "Region", "Base", "Size", "End", "Gap"); printf("------------------------------------------------\n"); -- cgit v1.3.1 From 299d24eddfeb18a7576187b3010d5462317335e9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:55 -0700 Subject: x86: Make do_zboot_states() static This function is only called within zboot.c so make the function private. Signed-off-by: Simon Glass --- cmd/x86/zboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 94e602b8a5b..3035172352a 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -119,8 +119,8 @@ U_BOOT_SUBCMDS(zboot, U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""), ) -int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[], int state_mask) +static int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[], int state_mask) { int ret = 0; -- cgit v1.3.1 From 2de073527bb92b47d49366249cd3fdea5016bcaf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:57 -0700 Subject: x86: Drop duplicate definition of zimage_dump() This is now defined in bootm.h so drop the duplicate in the x86 code. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 8 -------- cmd/x86/zboot.c | 1 + 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'cmd') diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 8b542605170..76b2a797ccf 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -71,14 +71,6 @@ struct zboot_state { extern struct zboot_state state; -/** - * zimage_dump() - Dump information about a zimage - * - * @base_ptr: Pointer to the boot parameters - * @show_cmdline: true to show the kernel command line - */ -void zimage_dump(struct boot_params *base_ptr, bool show_cmdline); - /** * zboot_load() - Load a zimage * diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 3035172352a..40f67a75593 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_BOOT +#include #include #include #include -- cgit v1.3.1 From 00cfb598e740d8bad79097e7e069ad71d86bbd5a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:24:59 -0700 Subject: x86: Rename state to bmi Use the common name for the struct, in preparation for passing it around between functions. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 2 +- arch/x86/lib/zimage.c | 48 +++++++++++++++++++++---------------------- cmd/x86/zboot.c | 4 ++-- 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'cmd') diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 13a08850dfb..b592057e58b 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -42,7 +42,7 @@ enum { ZBOOT_STATE_COUNT = 5, }; -extern struct bootm_info state; +extern struct bootm_info bmi; /** * zboot_load() - Load a zimage diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 1dbebfe8afd..991d0c84006 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -56,7 +56,7 @@ DECLARE_GLOBAL_DATA_PTR; #define COMMAND_LINE_SIZE 2048 /* Current state of the boot */ -struct bootm_info state; +struct bootm_info bmi; static void build_command_line(char *command_line, int auto_boot) { @@ -371,8 +371,8 @@ int zboot_load(void) struct boot_params *base_ptr; int ret; - if (state.base_ptr) { - struct boot_params *from = (struct boot_params *)state.base_ptr; + if (bmi.base_ptr) { + struct boot_params *from = (struct boot_params *)bmi.base_ptr; base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE; log_debug("Building boot_params at 0x%8.8lx\n", @@ -380,18 +380,18 @@ int zboot_load(void) memset(base_ptr, '\0', sizeof(*base_ptr)); base_ptr->hdr = from->hdr; } else { - base_ptr = load_zimage((void *)state.bzimage_addr, state.bzimage_size, - &state.load_address); + base_ptr = load_zimage((void *)bmi.bzimage_addr, bmi.bzimage_size, + &bmi.load_address); if (!base_ptr) { puts("## Kernel loading failed ...\n"); return -EINVAL; } } - state.base_ptr = base_ptr; + bmi.base_ptr = base_ptr; - ret = env_set_hex("zbootbase", map_to_sysmem(state.base_ptr)); + ret = env_set_hex("zbootbase", map_to_sysmem(bmi.base_ptr)); if (!ret) - ret = env_set_hex("zbootaddr", state.load_address); + ret = env_set_hex("zbootaddr", bmi.load_address); if (ret) return ret; @@ -400,12 +400,12 @@ int zboot_load(void) int zboot_setup(void) { - struct boot_params *base_ptr = state.base_ptr; + struct boot_params *base_ptr = bmi.base_ptr; int ret; ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET, - 0, state.initrd_addr, state.initrd_size, - (ulong)state.cmdline); + 0, bmi.initrd_addr, bmi.initrd_size, + (ulong)bmi.cmdline); if (ret) return -EINVAL; @@ -414,7 +414,7 @@ int zboot_setup(void) int zboot_go(void) { - struct boot_params *params = state.base_ptr; + struct boot_params *params = bmi.base_ptr; struct setup_header *hdr = ¶ms->hdr; bool image_64bit; ulong entry; @@ -422,7 +422,7 @@ int zboot_go(void) disable_interrupts(); - entry = state.load_address; + entry = bmi.load_address; image_64bit = false; if (IS_ENABLED(CONFIG_X86_RUN_64BIT) && (hdr->xloadflags & XLF_KERNEL_64)) { @@ -430,7 +430,7 @@ int zboot_go(void) } /* we assume that the kernel is in place */ - ret = boot_linux_kernel((ulong)state.base_ptr, entry, image_64bit); + ret = boot_linux_kernel((ulong)bmi.base_ptr, entry, image_64bit); return ret; } @@ -596,7 +596,7 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) print_num("Start sys seg", hdr->start_sys_seg); print_num("Kernel version", hdr->kernel_version); version = zimage_get_kernel_version(base_ptr, - (void *)state.bzimage_addr); + (void *)bmi.bzimage_addr); if (version) printf(" @%p: %s\n", version, version); print_num("Type of loader", hdr->type_of_loader); @@ -642,22 +642,22 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, ulong initrd_size, ulong base_addr, const char *cmdline) { - bootm_init(&state); + bootm_init(&bmi); - state.bzimage_size = bzimage_size; - state.initrd_addr = initrd_addr; - state.initrd_size = initrd_size; + bmi.bzimage_size = bzimage_size; + bmi.initrd_addr = initrd_addr; + bmi.initrd_size = initrd_size; if (base_addr) { - state.base_ptr = map_sysmem(base_addr, 0); - state.load_address = bzimage_addr; + bmi.base_ptr = map_sysmem(base_addr, 0); + bmi.load_address = bzimage_addr; } else { - state.bzimage_addr = bzimage_addr; + bmi.bzimage_addr = bzimage_addr; } - state.cmdline = cmdline; + bmi.cmdline = cmdline; } void zboot_info(void) { printf("Kernel loaded at %08lx, setup_base=%p\n", - state.load_address, state.base_ptr); + bmi.load_address, bmi.base_ptr); } diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 40f67a75593..0d0a8e53172 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -57,7 +57,7 @@ static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - if (!state.base_ptr) { + if (!bmi.base_ptr) { printf("base is not set: use 'zboot load' first\n"); return CMD_RET_FAILURE; } @@ -97,7 +97,7 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct boot_params *base_ptr = state.base_ptr; + struct boot_params *base_ptr = bmi.base_ptr; if (argc > 1) base_ptr = (void *)hextoul(argv[1], NULL); -- cgit v1.3.1 From 4e36b1739b03e81ff395959b58fe33e67c4d2233 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:00 -0700 Subject: x86: Move the bootm state for zimage into cmd/ Rather than holding the state in the implementation code, move it to the command code. The state is now passed to the implementation functions and can there (with future work) be pass in from bootstd, without going through the commands. Signed-off-by: Simon Glass --- arch/x86/include/asm/zimage.h | 22 +++++++------ arch/x86/lib/zimage.c | 75 +++++++++++++++++++++---------------------- cmd/bootflow.c | 5 ++- cmd/x86/zboot.c | 20 ++++++++---- include/bootm.h | 8 +++-- 5 files changed, 73 insertions(+), 57 deletions(-) (limited to 'cmd') diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index b592057e58b..4ed6d8d5cc2 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -10,6 +10,8 @@ #include #include +struct bootm_info; + /* linux i386 zImage/bzImage header. Offsets relative to * the start of the image */ @@ -42,8 +44,6 @@ enum { ZBOOT_STATE_COUNT = 5, }; -extern struct bootm_info bmi; - /** * zboot_load() - Load a zimage * @@ -51,21 +51,21 @@ extern struct bootm_info bmi; * * Return: 0 if OK, -ve on error */ -int zboot_load(void); +int zboot_load(struct bootm_info *bmi); /** * zboot_setup() - Set up the zboot image reeady for booting * * Return: 0 if OK, -ve on error */ -int zboot_setup(void); +int zboot_setup(struct bootm_info *bmi); /** * zboot_go() - Start the image * * Return: 0 if OK, -ve on error */ -int zboot_go(void); +int zboot_go(struct bootm_info *bmi); /** * load_zimage() - Load a zImage or bzImage @@ -104,6 +104,7 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, * * Record information about a zimage so it can be booted * + * @bmi: Bootm information * @bzimage_addr: Address of the bzImage to boot * @bzimage_size: Size of the bzImage, or 0 to detect this * @initrd_addr: Address of the initial ramdisk, or 0 if none @@ -114,14 +115,17 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, * @cmdline: Environment variable containing the 'override' command line, or * NULL to use the one in the setup block */ -void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, - ulong initrd_size, ulong base_addr, const char *cmdline); +void zboot_start(struct bootm_info *bmi, ulong bzimage_addr, ulong bzimage_size, + ulong initrd_addr, ulong initrd_size, ulong base_addr, + const char *cmdline); /** * zboot_info() - Show simple info about a zimage * - * Shows wherer the kernel was loaded and also the setup base + * Shows where the kernel was loaded and also the setup base + * + * @bmi: Bootm information */ -void zboot_info(void); +void zboot_info(struct bootm_info *bmi); #endif diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 991d0c84006..7f4b117b403 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -55,9 +55,6 @@ DECLARE_GLOBAL_DATA_PTR; #define COMMAND_LINE_SIZE 2048 -/* Current state of the boot */ -struct bootm_info bmi; - static void build_command_line(char *command_line, int auto_boot) { char *env_command_line; @@ -366,13 +363,13 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, return 0; } -int zboot_load(void) +int zboot_load(struct bootm_info *bmi) { struct boot_params *base_ptr; int ret; - if (bmi.base_ptr) { - struct boot_params *from = (struct boot_params *)bmi.base_ptr; + if (bmi->base_ptr) { + struct boot_params *from = (struct boot_params *)bmi->base_ptr; base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE; log_debug("Building boot_params at 0x%8.8lx\n", @@ -380,41 +377,41 @@ int zboot_load(void) memset(base_ptr, '\0', sizeof(*base_ptr)); base_ptr->hdr = from->hdr; } else { - base_ptr = load_zimage((void *)bmi.bzimage_addr, bmi.bzimage_size, - &bmi.load_address); + base_ptr = load_zimage((void *)bmi->bzimage_addr, + bmi->bzimage_size, &bmi->load_address); if (!base_ptr) { puts("## Kernel loading failed ...\n"); return -EINVAL; } } - bmi.base_ptr = base_ptr; + bmi->base_ptr = base_ptr; - ret = env_set_hex("zbootbase", map_to_sysmem(bmi.base_ptr)); + ret = env_set_hex("zbootbase", map_to_sysmem(bmi->base_ptr)); if (!ret) - ret = env_set_hex("zbootaddr", bmi.load_address); + ret = env_set_hex("zbootaddr", bmi->load_address); if (ret) return ret; return 0; } -int zboot_setup(void) +int zboot_setup(struct bootm_info *bmi) { - struct boot_params *base_ptr = bmi.base_ptr; + struct boot_params *base_ptr = bmi->base_ptr; int ret; ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET, - 0, bmi.initrd_addr, bmi.initrd_size, - (ulong)bmi.cmdline); + 0, bmi->initrd_addr, bmi->initrd_size, + (ulong)bmi->cmdline); if (ret) return -EINVAL; return 0; } -int zboot_go(void) +int zboot_go(struct bootm_info *bmi) { - struct boot_params *params = bmi.base_ptr; + struct boot_params *params = bmi->base_ptr; struct setup_header *hdr = ¶ms->hdr; bool image_64bit; ulong entry; @@ -422,7 +419,7 @@ int zboot_go(void) disable_interrupts(); - entry = bmi.load_address; + entry = bmi->load_address; image_64bit = false; if (IS_ENABLED(CONFIG_X86_RUN_64BIT) && (hdr->xloadflags & XLF_KERNEL_64)) { @@ -430,7 +427,7 @@ int zboot_go(void) } /* we assume that the kernel is in place */ - ret = boot_linux_kernel((ulong)bmi.base_ptr, entry, image_64bit); + ret = boot_linux_kernel((ulong)bmi->base_ptr, entry, image_64bit); return ret; } @@ -438,16 +435,18 @@ int zboot_go(void) int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size, ulong base, char *cmdline) { + struct bootm_info bmi; int ret; - zboot_start(addr, size, initrd, initrd_size, base, cmdline); - ret = zboot_load(); + bootm_init(&bmi); + zboot_start(&bmi, addr, size, initrd, initrd_size, base, cmdline); + ret = zboot_load(&bmi); if (ret) return log_msg_ret("ld", ret); - ret = zboot_setup(); + ret = zboot_setup(&bmi); if (ret) return log_msg_ret("set", ret); - ret = zboot_go(); + ret = zboot_go(&bmi); if (ret) return log_msg_ret("go", ret); @@ -555,7 +554,8 @@ static void show_loader(struct setup_header *hdr) printf("\n"); } -void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) +void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, + bool show_cmdline) { struct setup_header *hdr; const char *version; @@ -596,7 +596,7 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) print_num("Start sys seg", hdr->start_sys_seg); print_num("Kernel version", hdr->kernel_version); version = zimage_get_kernel_version(base_ptr, - (void *)bmi.bzimage_addr); + (void *)bmi->bzimage_addr); if (version) printf(" @%p: %s\n", version, version); print_num("Type of loader", hdr->type_of_loader); @@ -639,25 +639,24 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline) print_num("Kernel info offset", hdr->kernel_info_offset); } -void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr, - ulong initrd_size, ulong base_addr, const char *cmdline) +void zboot_start(struct bootm_info *bmi, ulong bzimage_addr, ulong bzimage_size, + ulong initrd_addr, ulong initrd_size, ulong base_addr, + const char *cmdline) { - bootm_init(&bmi); - - bmi.bzimage_size = bzimage_size; - bmi.initrd_addr = initrd_addr; - bmi.initrd_size = initrd_size; + bmi->bzimage_size = bzimage_size; + bmi->initrd_addr = initrd_addr; + bmi->initrd_size = initrd_size; if (base_addr) { - bmi.base_ptr = map_sysmem(base_addr, 0); - bmi.load_address = bzimage_addr; + bmi->base_ptr = map_sysmem(base_addr, 0); + bmi->load_address = bzimage_addr; } else { - bmi.bzimage_addr = bzimage_addr; + bmi->bzimage_addr = bzimage_addr; } - bmi.cmdline = cmdline; + bmi->cmdline = cmdline; } -void zboot_info(void) +void zboot_info(struct bootm_info *bmi) { printf("Kernel loaded at %08lx, setup_base=%p\n", - bmi.load_address, bmi.base_ptr); + bmi->load_address, bmi->base_ptr); } diff --git a/cmd/bootflow.c b/cmd/bootflow.c index f88995a478f..72b06a42e4d 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -380,7 +380,10 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, bflow = std->cur_bootflow; if (IS_ENABLED(CONFIG_X86) && x86_setup) { - zimage_dump(bflow->x86_setup, false); + struct bootm_info bmi; + + bootm_init(&bmi); + zimage_dump(&bmi, bflow->x86_setup, false); return 0; } diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 0d0a8e53172..029ff4eb9fd 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -13,6 +13,9 @@ #include #include +/* Current state of the boot */ +static struct bootm_info bmi; + static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -21,6 +24,8 @@ static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc, ulong base_addr; int i; + bootm_init(&bmi); + log_debug("argc %d:", argc); for (i = 0; i < argc; i++) log_debug(" %s", argv[i]); @@ -36,7 +41,7 @@ static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc, base_addr = argc > 5 ? hextoul(argv[5], NULL) : 0; cmdline = argc > 6 ? env_get(argv[6]) : NULL; - zboot_start(bzimage_addr, bzimage_size, initrd_addr, initrd_size, + zboot_start(&bmi, bzimage_addr, bzimage_size, initrd_addr, initrd_size, base_addr, cmdline); return 0; @@ -47,7 +52,7 @@ static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc, { int ret; - ret = zboot_load(); + ret = zboot_load(&bmi); if (ret) return ret; @@ -61,12 +66,13 @@ static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc, printf("base is not set: use 'zboot load' first\n"); return CMD_RET_FAILURE; } - if (zboot_setup()) { + + if (zboot_setup(&bmi)) { puts("Setting up boot parameters failed ...\n"); return CMD_RET_FAILURE; } - if (zboot_setup()) + if (zboot_setup(&bmi)) return CMD_RET_FAILURE; return 0; @@ -75,7 +81,7 @@ static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - zboot_info(); + zboot_info(&bmi); return 0; } @@ -85,7 +91,7 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc, { int ret; - ret = zboot_go(); + ret = zboot_go(&bmi); if (ret) { printf("Kernel returned! (err=%d)\n", ret); return CMD_RET_FAILURE; @@ -105,7 +111,7 @@ static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc, printf("No zboot setup_base\n"); return CMD_RET_FAILURE; } - zimage_dump(base_ptr, true); + zimage_dump(&bmi, base_ptr, true); return 0; } diff --git a/include/bootm.h b/include/bootm.h index 5fa9761629e..fe7f80b88a5 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -92,6 +92,8 @@ struct bootm_info { /** * bootm_init() - Set up a bootm_info struct with useful defaults * + * @bmi: Bootm information + * * Set up the struct with default values for all members: * @boot_progress is set to true and @images is set to the global images * variable. Everything else is set to NULL except @argc which is 0 @@ -107,7 +109,7 @@ void bootm_init(struct bootm_info *bmi); * - disabled interrupts. * * @flag: Flags indicating what to do (BOOTM_STATE_...) - * bmi: Bootm information + * @bmi: Bootm information * Return: 1 on error. On success the OS boots so this function does * not return. */ @@ -340,11 +342,13 @@ const char *zimage_get_kernel_version(struct boot_params *params, * * This shows all available information in a zimage that has been loaded. * + * @bmi: Bootm information * @base_ptr: Pointer to the boot parameters, typically at address * DEFAULT_SETUP_BASE * @show_cmdline: true to show the full command line */ -void zimage_dump(struct boot_params *base_ptr, bool show_cmdline); +void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, + bool show_cmdline); /* * bootm_boot_start() - Boot an image at the given address -- cgit v1.3.1 From 1592ff27d502efdc79992f57c07ff0cf81bc9305 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:01 -0700 Subject: bootstd: Correct display of kernel version The address of the bzImage is not recorded in the bootflow, so we cannot actually locate the version at present. Handle this case, to avoid showing invalid data. Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 13 ++++++++----- cmd/bootflow.c | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'cmd') diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 7f4b117b403..d71285e71d9 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -558,7 +558,6 @@ void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, bool show_cmdline) { struct setup_header *hdr; - const char *version; int i; printf("Setup located at %p:\n\n", base_ptr); @@ -595,10 +594,14 @@ void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, print_num("Real mode switch", hdr->realmode_swtch); print_num("Start sys seg", hdr->start_sys_seg); print_num("Kernel version", hdr->kernel_version); - version = zimage_get_kernel_version(base_ptr, - (void *)bmi->bzimage_addr); - if (version) - printf(" @%p: %s\n", version, version); + if (bmi->bzimage_addr) { + const char *version; + + version = zimage_get_kernel_version(base_ptr, + (void *)bmi->bzimage_addr); + if (version) + printf(" @%p: %s\n", version, version); + } print_num("Type of loader", hdr->type_of_loader); show_loader(hdr); print_num("Load flags", hdr->loadflags); diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 72b06a42e4d..da17fd93b8b 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -383,6 +383,8 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, struct bootm_info bmi; bootm_init(&bmi); + /* we don't know this at present */ + bootm_x86_set(&bmi, bzimage_addr, 0); zimage_dump(&bmi, bflow->x86_setup, false); return 0; -- cgit v1.3.1 From c73da92304280b229e3d8dfd565fae5a24fe3ce8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:02 -0700 Subject: x86: Drop the unnecessary base_ptr argument to zboot_dump() This value is include the bootm_info, so drop the unnecessary parameter. Signed-off-by: Simon Glass --- arch/x86/lib/zimage.c | 5 +++-- cmd/bootflow.c | 3 ++- cmd/x86/zboot.c | 8 +++----- include/bootm.h | 7 ++----- 4 files changed, 10 insertions(+), 13 deletions(-) (limited to 'cmd') diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index d71285e71d9..145ba0b8ea0 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -554,12 +554,13 @@ static void show_loader(struct setup_header *hdr) printf("\n"); } -void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, - bool show_cmdline) +void zimage_dump(struct bootm_info *bmi, bool show_cmdline) { + struct boot_params *base_ptr; struct setup_header *hdr; int i; + base_ptr = bmi->base_ptr; printf("Setup located at %p:\n\n", base_ptr); print_num64("ACPI RSDP addr", base_ptr->acpi_rsdp_addr); diff --git a/cmd/bootflow.c b/cmd/bootflow.c index da17fd93b8b..6d0be320bdb 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -385,7 +385,8 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, bootm_init(&bmi); /* we don't know this at present */ bootm_x86_set(&bmi, bzimage_addr, 0); - zimage_dump(&bmi, bflow->x86_setup, false); + bootm_x86_set(&bmi, base_ptr, bflow->x86_setup); + zimage_dump(&bmi, false); return 0; } diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c index 029ff4eb9fd..ee099ca041b 100644 --- a/cmd/x86/zboot.c +++ b/cmd/x86/zboot.c @@ -103,15 +103,13 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc, static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - struct boot_params *base_ptr = bmi.base_ptr; - if (argc > 1) - base_ptr = (void *)hextoul(argv[1], NULL); - if (!base_ptr) { + bmi.base_ptr = (void *)hextoul(argv[1], NULL); + if (!bmi.base_ptr) { printf("No zboot setup_base\n"); return CMD_RET_FAILURE; } - zimage_dump(&bmi, base_ptr, true); + zimage_dump(&bmi, true); return 0; } diff --git a/include/bootm.h b/include/bootm.h index fe7f80b88a5..c471615b08c 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -342,13 +342,10 @@ const char *zimage_get_kernel_version(struct boot_params *params, * * This shows all available information in a zimage that has been loaded. * - * @bmi: Bootm information - * @base_ptr: Pointer to the boot parameters, typically at address - * DEFAULT_SETUP_BASE + * @bmi: Bootm information, with valid base_ptr * @show_cmdline: true to show the full command line */ -void zimage_dump(struct bootm_info *bmi, struct boot_params *base_ptr, - bool show_cmdline); +void zimage_dump(struct bootm_info *bmi, bool show_cmdline); /* * bootm_boot_start() - Boot an image at the given address -- cgit v1.3.1 From 2c04afbc957d18e61813315a0694db903754a280 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:15 -0700 Subject: net: Keep the bootstage functions together Move the bootstage_mark() function just before net_loop(), so that the IPv6 code is not in the way. Signed-off-by: Simon Glass --- cmd/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index 79525f73a51..deebd5b710f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -413,8 +413,6 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, return CMD_RET_USAGE; } - bootstage_mark(BOOTSTAGE_ID_NET_START); - if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; size_t len; @@ -428,6 +426,8 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } + bootstage_mark(BOOTSTAGE_ID_NET_START); + size = net_loop(proto); if (size < 0) { bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); -- cgit v1.3.1 From 3ccbc10cd9e3b28d67fe5008943a648b870db1e6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:16 -0700 Subject: net: Tidy up the comments to parse_args() This function is a bit vague as to what it does. Expand the comment a little, to specify which args are provided and which variables are updated. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- cmd/net.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index deebd5b710f..89a4d9b38d4 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -313,9 +313,18 @@ static int parse_addr_size(char * const argv[]) /** * parse_args() - parse command line arguments * + * Sets: + * + * - net_boot_file_name_explicit to true if a filename was specified + * - net_boot_file_name to that filename, if specified, else the value of the + * 'bootfile' environment variable + * - image_load_addr if a load address was provided + * - image_save_addr and image_save_size, if proto == TFTPPUT + * * @proto: command prototype - * @argc: number of arguments - * @argv: command line arguments + * @argc: number of arguments, include the command, which has already been + * parsed + * @argv: command line arguments, with argv[0] being the command * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[]) -- cgit v1.3.1 From f1ece5d86e5577ae9bb3325d65ed7003f3cbaf9e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:17 -0700 Subject: net: Simplify parse_args() This function repeats the same code in a few places, namely setting net_boot_file_name_explicit and copying of the filename to net_boot_file_name Move these two operations to the caller, with just the filename (or NULL) returned by parse_args() This makes things a little easier to follow. Signed-off-by: Simon Glass --- cmd/net.c | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index 89a4d9b38d4..cc7d14eb082 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -314,10 +314,6 @@ static int parse_addr_size(char * const argv[]) * parse_args() - parse command line arguments * * Sets: - * - * - net_boot_file_name_explicit to true if a filename was specified - * - net_boot_file_name to that filename, if specified, else the value of the - * 'bootfile' environment variable * - image_load_addr if a load address was provided * - image_save_addr and image_save_size, if proto == TFTPPUT * @@ -325,21 +321,20 @@ static int parse_addr_size(char * const argv[]) * @argc: number of arguments, include the command, which has already been * parsed * @argv: command line arguments, with argv[0] being the command + * @fnamep: set to the filename, if provided, else NULL * Return: 0 on success */ -static int parse_args(enum proto_t proto, int argc, char *const argv[]) +static int parse_args(enum proto_t proto, int argc, char *const argv[], + const char **fnamep) { ulong addr; char *end; + *fnamep = NULL; switch (argc) { case 1: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) return 1; - - /* refresh bootfile name from env */ - copy_filename(net_boot_file_name, env_get("bootfile"), - sizeof(net_boot_file_name)); break; case 2: @@ -352,16 +347,10 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) * mis-interpreted as a valid number. */ addr = hextoul(argv[1], &end); - if (end == (argv[1] + strlen(argv[1]))) { + if (end == (argv[1] + strlen(argv[1]))) image_load_addr = addr; - /* refresh bootfile name from env */ - copy_filename(net_boot_file_name, env_get("bootfile"), - sizeof(net_boot_file_name)); - } else { - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[1], - sizeof(net_boot_file_name)); - } + else + *fnamep = argv[1]; break; case 3: @@ -370,9 +359,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) return 1; } else { image_load_addr = hextoul(argv[1], NULL); - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[2], - sizeof(net_boot_file_name)); + *fnamep = argv[2]; } break; @@ -380,20 +367,20 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[]) case 4: if (parse_addr_size(argv)) return 1; - net_boot_file_name_explicit = true; - copy_filename(net_boot_file_name, argv[3], - sizeof(net_boot_file_name)); + *fnamep = argv[3]; break; #endif default: return 1; } + return 0; } static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { + const char *fname; char *s; int rcode = 0; int size; @@ -417,11 +404,19 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv)) { + if (parse_args(proto, argc, argv, &fname)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } + if (fname) { + net_boot_file_name_explicit = true; + } else { + net_boot_file_name_explicit = false; + fname = env_get("bootfile"); + } + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; size_t len; -- cgit v1.3.1 From 4b6070e056fc2c11b7621c32151f95f7a045ac01 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:18 -0700 Subject: net: Return the load address from parse_args() Rather than updating the global, update the value of a parameter, so the action of the function is simpler. Signed-off-by: Simon Glass --- cmd/net.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index cc7d14eb082..d15d344cb54 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -314,7 +314,6 @@ static int parse_addr_size(char * const argv[]) * parse_args() - parse command line arguments * * Sets: - * - image_load_addr if a load address was provided * - image_save_addr and image_save_size, if proto == TFTPPUT * * @proto: command prototype @@ -322,10 +321,12 @@ static int parse_addr_size(char * const argv[]) * parsed * @argv: command line arguments, with argv[0] being the command * @fnamep: set to the filename, if provided, else NULL + * @addrp: returns the load address, if any is provided, else it is left + * unchanged * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[], - const char **fnamep) + const char **fnamep, ulong *addrp) { ulong addr; char *end; @@ -348,7 +349,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], */ addr = hextoul(argv[1], &end); if (end == (argv[1] + strlen(argv[1]))) - image_load_addr = addr; + *addrp = addr; else *fnamep = argv[1]; break; @@ -358,7 +359,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], if (parse_addr_size(argv)) return 1; } else { - image_load_addr = hextoul(argv[1], NULL); + *addrp = hextoul(argv[1], NULL); *fnamep = argv[2]; } break; @@ -404,7 +405,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv, &fname)) { + if (parse_args(proto, argc, argv, &fname, &image_load_addr)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } -- cgit v1.3.1 From f60421204816bd0aa40e9e43c18d4bc5861d3521 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:19 -0700 Subject: net: Return the address and size from parse_addr_size() Rather than updating the global, update the value of some parameters, so the action of the function is simpler. Signed-off-by: Simon Glass --- cmd/net.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index d15d344cb54..cc968e9460f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -297,13 +297,15 @@ static void netboot_update_env(void) /** * parse_addr_size() - parse address and size arguments for tftpput * - * @argv: command line arguments + * @argv: command line arguments (argv[1] and argv[2] must be valid) + * @addrp: returns the address, on success + * @sizep: returns the size, on success * Return: 0 on success */ -static int parse_addr_size(char * const argv[]) +static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep) { - if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 || - strict_strtoul(argv[2], 16, &image_save_size) < 0) { + if (strict_strtoul(argv[1], 16, addrp) < 0 || + strict_strtoul(argv[2], 16, sizep) < 0) { printf("Invalid address/size\n"); return CMD_RET_USAGE; } @@ -356,7 +358,8 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], case 3: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - if (parse_addr_size(argv)) + if (parse_addr_size(argv, &image_save_addr, + &image_save_size)) return 1; } else { *addrp = hextoul(argv[1], NULL); @@ -366,7 +369,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], #ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv)) + if (parse_addr_size(argv, &image_save_addr, &image_save_size)) return 1; *fnamep = argv[3]; break; -- cgit v1.3.1 From 25d51d3c798f6e256daa628bb2a9fcc36fde0382 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:20 -0700 Subject: net: Return the size from parse_args() Rather than setting global variables, return the size, if provided. For tftput, use the addr argument to store the save address, to avoid adding yet another parameter. Signed-off-by: Simon Glass --- cmd/net.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index cc968e9460f..572fa75a72f 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -323,12 +323,14 @@ static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep) * parsed * @argv: command line arguments, with argv[0] being the command * @fnamep: set to the filename, if provided, else NULL - * @addrp: returns the load address, if any is provided, else it is left + * @addrp: returns the load/save address, if any is provided, else it is + * left unchanged + * @sizep: returns the save size, if any is provided, else it is left * unchanged * Return: 0 on success */ static int parse_args(enum proto_t proto, int argc, char *const argv[], - const char **fnamep, ulong *addrp) + const char **fnamep, ulong *addrp, ulong *sizep) { ulong addr; char *end; @@ -358,8 +360,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], case 3: if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - if (parse_addr_size(argv, &image_save_addr, - &image_save_size)) + if (parse_addr_size(argv, addrp, sizep)) return 1; } else { *addrp = hextoul(argv[1], NULL); @@ -369,7 +370,7 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], #ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv, &image_save_addr, &image_save_size)) + if (parse_addr_size(argv, addrp, sizep)) return 1; *fnamep = argv[3]; break; @@ -385,6 +386,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { const char *fname; + ulong addr; char *s; int rcode = 0; int size; @@ -392,10 +394,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, net_boot_file_name_explicit = false; *net_boot_file_name = '\0'; - /* pre-set image_load_addr */ + /* pre-set addr */ s = env_get("loadaddr"); if (s != NULL) - image_load_addr = hextoul(s, NULL); + addr = hextoul(s, NULL); if (IS_ENABLED(CONFIG_IPV6)) { use_ip6 = false; @@ -408,10 +410,14 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv, &fname, &image_load_addr)) { + if (parse_args(proto, argc, argv, &fname, &addr, &image_save_size)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; if (fname) { net_boot_file_name_explicit = true; -- cgit v1.3.1 From bfffdfaaf6f492865100197a5b141482799afc09 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:21 -0700 Subject: net: Refactor part of netboot_common() into a function Move the core code for starting an netboot operation into a separate function, so that we can (with additional work) move towards calling it from outside the file. Signed-off-by: Simon Glass --- cmd/net.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 16 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index 572fa75a72f..f980448e0ef 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -382,11 +382,50 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], return 0; } +static int netboot_run_(enum proto_t proto, ulong addr, const char *fname, + ulong size, bool fname_explicit, bool ipv6) +{ + int ret; + + bootstage_mark(BOOTSTAGE_ID_NET_START); + + /* + * For now we use the global variables as that is the only way to + * control the network stack. At some point, perhaps, the state could be + * in a struct + */ + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; + + net_boot_file_name_explicit = fname_explicit; + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6)) + use_ip6 = ipv6; + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { + image_save_addr = addr; + image_save_size = size; + } else { + image_load_addr = addr; + } + + ret = net_loop(proto); + if (ret < 0) { + bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + return ret; + } + bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); + + return 0; +} + static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { + ulong addr, save_size; + bool fname_explicit; const char *fname; - ulong addr; char *s; int rcode = 0; int size; @@ -410,22 +449,17 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - if (parse_args(proto, argc, argv, &fname, &addr, &image_save_size)) { + if (parse_args(proto, argc, argv, &fname, &addr, &save_size)) { bootstage_error(BOOTSTAGE_ID_NET_START); return CMD_RET_USAGE; } - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) - image_save_addr = addr; - else - image_load_addr = addr; if (fname) { - net_boot_file_name_explicit = true; + fname_explicit = true; } else { - net_boot_file_name_explicit = false; + fname_explicit = false; fname = env_get("bootfile"); } - copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) { char *s, *e; @@ -440,14 +474,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } } - bootstage_mark(BOOTSTAGE_ID_NET_START); - - size = net_loop(proto); - if (size < 0) { - bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + size = netboot_run_(proto, addr, fname, save_size, fname_explicit, + use_ip6); + if (size < 0) return CMD_RET_FAILURE; - } - bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); /* net_loop ok, update environment */ netboot_update_env(); -- cgit v1.3.1 From f278f0cb4996398720328ce33e057678f6ea4109 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:22 -0700 Subject: net: Drop #ifdef in parse_args() Use IS_ENABLED() to avoid an extra build path. Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- cmd/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index f980448e0ef..6d1c6374f76 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -368,13 +368,13 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], } break; -#ifdef CONFIG_CMD_TFTPPUT case 4: - if (parse_addr_size(argv, addrp, sizep)) - return 1; - *fnamep = argv[3]; - break; -#endif + if (IS_ENABLED(CONFIG_CMD_TFTPPUT)) { + if (parse_addr_size(argv, addrp, sizep)) + return 1; + *fnamep = argv[3]; + break; + } default: return 1; } -- cgit v1.3.1 From 0f094b8b146679c3980cd2febde4e902bbc4405d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Mar 2025 17:25:23 -0700 Subject: net: Provide a function to run network operations Add a new netboot_run() function which can be used for simple network operations, such as loading a file. Put the implementation in an internal function, used by the existing code. Place this function into the net/ code, so that it does not need the command line to be available. Document which network operations are supported, i.e. a limited subset, for now. For the one board which uses lwip, it is not quite clear how to avoid using the cmdline interface. This will need some discussion. Signed-off-by: Simon Glass --- cmd/net.c | 40 +--------------------------------------- include/net-common.h | 30 ++++++++++++++++++++++++++++++ net/net.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 39 deletions(-) (limited to 'cmd') diff --git a/cmd/net.c b/cmd/net.c index 6d1c6374f76..8f33c9f55d5 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -382,44 +382,6 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[], return 0; } -static int netboot_run_(enum proto_t proto, ulong addr, const char *fname, - ulong size, bool fname_explicit, bool ipv6) -{ - int ret; - - bootstage_mark(BOOTSTAGE_ID_NET_START); - - /* - * For now we use the global variables as that is the only way to - * control the network stack. At some point, perhaps, the state could be - * in a struct - */ - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) - image_save_addr = addr; - else - image_load_addr = addr; - - net_boot_file_name_explicit = fname_explicit; - copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); - if (IS_ENABLED(CONFIG_IPV6)) - use_ip6 = ipv6; - if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { - image_save_addr = addr; - image_save_size = size; - } else { - image_load_addr = addr; - } - - ret = net_loop(proto); - if (ret < 0) { - bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); - return ret; - } - bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); - - return 0; -} - static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, char *const argv[]) { @@ -475,7 +437,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc, } size = netboot_run_(proto, addr, fname, save_size, fname_explicit, - use_ip6); + IS_ENABLED(CONFIG_IPV6) && use_ip6); if (size < 0) return CMD_RET_FAILURE; diff --git a/include/net-common.h b/include/net-common.h index 29d31f37263..210042fc337 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -474,6 +474,36 @@ int net_init(void); enum proto_t; int net_loop(enum proto_t protocol); +/* internal function: do not use! */ +int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool fname_explicit, bool ipv6); + +/** + * netboot_run() - Run a network operation + * + * The following proto values are NOT supported: + * PING, since net_ping_ip cannot be set + * NETCONS, since its parameters cannot bet set + * RS, since first_call cannot be set, along with perhaps other things + * UDP, since udp_ops cannot be set + * DNS, since net_dns_resolve and net_dns_env_var cannot be set + * WGET, since DNS must be done first and that is not supported + * DHCP6, since the required parameters cannot be passed in + * + * To support one of these, either add the required arguments or perhaps a + * separate function and a struct to hold the information. + * + * @proto: Operation to run: TFTPGET, FASTBOOT_UDP, FASTBOOT_TCP, BOOTP, + * TFTPPUT, RARP, NFS, DHCP + * @addr: Load/save address + * @fname: Filename + * @size: Save size (not used for TFTPGET) + * @ipv6: true to use IPv6, false to use IPv4 + * Return 0 on success, else -ve error code + */ +int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool ipv6); + /** * dhcp_run() - Run DHCP on the current ethernet device * diff --git a/net/net.c b/net/net.c index 1828f1cca36..ef97377cdec 100644 --- a/net/net.c +++ b/net/net.c @@ -775,6 +775,50 @@ done: return ret; } +int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool fname_explicit, bool ipv6) +{ + int ret; + + bootstage_mark(BOOTSTAGE_ID_NET_START); + + /* + * For now we use the global variables as that is the only way to + * control the network stack. At some point, perhaps, the state could be + * in a struct + */ + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) + image_save_addr = addr; + else + image_load_addr = addr; + + net_boot_file_name_explicit = fname_explicit; + copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name)); + if (IS_ENABLED(CONFIG_IPV6)) + use_ip6 = ipv6; + if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) { + image_save_addr = addr; + image_save_size = size; + } else { + image_load_addr = addr; + } + + ret = net_loop(proto); + if (ret < 0) { + bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); + return ret; + } + bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); + + return 0; +} + +int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size, + bool ipv6) +{ + return netboot_run_(proto, addr, fname, size, true, ipv6); +} + /**********************************************************************/ static void start_again_timeout_handler(void) -- cgit v1.3.1 From 54c39bf104017e3a0b30fdff6104141b719af9ef Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Mon, 17 Mar 2025 14:04:01 +0530 Subject: blkmap: add an attribute to preserve the mem mapping Some blkmap memory mapped devices might have to be relevant even after U-Boot passes control to the next image as part of the platform boot. An example of such a mapping would be an OS installer ISO image, information for which has to be provided to the OS kernel. Use the 'preserve' attribute for such mappings. The code for adding a pmem node to the device-tree then checks if this attribute is set, and adds a node only for mappings which have this attribute. Signed-off-by: Sughosh Ganu Reviewed-by: Tobias Waldekranz Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- cmd/blkmap.c | 9 +++++++-- drivers/block/blkmap.c | 19 +++++++++++++++---- drivers/block/blkmap_helper.c | 2 +- include/blkmap.h | 4 +++- 4 files changed, 26 insertions(+), 8 deletions(-) (limited to 'cmd') diff --git a/cmd/blkmap.c b/cmd/blkmap.c index 164f80f1387..86a123b1cd3 100644 --- a/cmd/blkmap.c +++ b/cmd/blkmap.c @@ -62,13 +62,18 @@ static int do_blkmap_map_mem(struct map_ctx *ctx, int argc, char *const argv[]) { phys_addr_t addr; int err; + bool preserve = false; if (argc < 2) return CMD_RET_USAGE; addr = hextoul(argv[1], NULL); - err = blkmap_map_pmem(ctx->dev, ctx->blknr, ctx->blkcnt, addr); + if (argc == 3 && !strcmp(argv[2], "preserve")) + preserve = true; + + err = blkmap_map_pmem(ctx->dev, ctx->blknr, ctx->blkcnt, addr, + preserve); if (err) { printf("Unable to map %#llx at block 0x" LBAF ": %d\n", (unsigned long long)addr, ctx->blknr, err); @@ -221,7 +226,7 @@ U_BOOT_CMD_WITH_SUBCMDS( "blkmap create