add bi-endian support to the libsa ufs reader and enable it in efiboot. ffs frontends to "ufs.c" now also define ufs_dinode_swap, ufs_indp_swap, and FS_MAGIC (moved from ufs.c #if segments.) these are used to call the right (32/64 bit) ffsv1/v2 version. ufs.c 'struct file' gains f_swapped member. accessors for d_magic, d_reclen, and d_ino are introduced (they need to be swapped.) sfter reading an inode from disk, read_inode() may call ufs_dinode_swap(). indirect block number and caches may be swapped. error handling in ffs_find_superblock() is cleaned up. (size is slightly reduced on some ports with this part.) defaults for new defines added to ufs.c. (XXX: we build ufs.c but i think all the consumers don't use it, and we can stop building it.) LFS support is not included. add a cut-down copy of ffs_bswap.c from the kernel. also enable bi-endian disklabel support in efiboot. several ports build and sizes compared for platforms that don't enable this code and all but one saw reduced code size. Index: sys/stand/efiboot/Makefile.efiboot =================================================================== RCS file: /cvsroot/src/sys/stand/efiboot/Makefile.efiboot,v retrieving revision 1.20 diff -p -u -r1.20 Makefile.efiboot --- sys/stand/efiboot/Makefile.efiboot 4 May 2021 19:07:19 -0000 1.20 +++ sys/stand/efiboot/Makefile.efiboot 26 May 2021 09:59:27 -0000 @@ -80,6 +80,8 @@ CPPFLAGS+= -DSUPPORT_DHCP #CPPFLAGS+= -DSUPPORT_NFS CPPFLAGS+= -DSUPPORT_TFTP CPPFLAGS+= -DLIBSA_ENABLE_LS_OP +CPPFLAGS+= -DLIBSA_FFS_EI +CPPFLAGS+= -DLIBSA_DISKLABEL_EI #CPPFLAGS+= -DEFIBOOT_DEBUG #CPPFLAGS+= -DARP_DEBUG Index: sys/stand/efiboot/version =================================================================== RCS file: /cvsroot/src/sys/stand/efiboot/version,v retrieving revision 1.24 diff -p -u -r1.24 version --- sys/stand/efiboot/version 26 May 2021 09:42:36 -0000 1.24 +++ sys/stand/efiboot/version 26 May 2021 09:59:27 -0000 @@ -28,3 +28,4 @@ is taken as the current. 2.5: Recognize the EFI system partion as fstype MSDOS. 2.6: Disable ACPI support when booting big endian kernels. 2.7: Add basic support for booting from RAID1 volumes. +2.8: Add bi-endian disklabel and FFS support. Index: sys/lib/libsa/Makefile =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/Makefile,v retrieving revision 1.94 diff -p -u -r1.94 Makefile --- sys/lib/libsa/Makefile 17 May 2021 08:50:36 -0000 1.94 +++ sys/lib/libsa/Makefile 26 May 2021 09:59:27 -0000 @@ -80,7 +80,7 @@ CPPFLAGS+= -DLIBSA_BIENDIAN_SUPPORT SRCS+= byteorder.c .endif -SRCS+= ffsv1.c ffsv2.c +SRCS+= ffsv1.c ffsv2.c ffs_bswap.c SRCS+= lfsv1.c lfsv2.c SRCS+= cd9660.c SRCS+= ustarfs.c Index: sys/lib/libsa/ffs_bswap.c =================================================================== RCS file: sys/lib/libsa/ffs_bswap.c diff -N sys/lib/libsa/ffs_bswap.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/lib/libsa/ffs_bswap.c 26 May 2021 09:59:27 -0000 @@ -0,0 +1,177 @@ +/* $NetBSD: ffs_bswap.c,v 1.40 2017/02/09 04:37:35 kre Exp $ */ + +/* + * Copyright (c) 1998 Manuel Bouyer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * This copy is a minimal version for libsa and it's ufs.c. The unused + * functions are removed, and additional swapping is performed on the + * di_extb, di_db, and di_ib arrays. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ffs_bswap.c,v 1.40 2017/02/09 04:37:35 kre Exp $"); + +#include +#include + +#include +#include +#include +#include +#include + +static void +libsa_ffs_csumtotal_swap(const struct csum_total *o, struct csum_total *n) +{ + n->cs_ndir = bswap64(o->cs_ndir); + n->cs_nbfree = bswap64(o->cs_nbfree); + n->cs_nifree = bswap64(o->cs_nifree); + n->cs_nffree = bswap64(o->cs_nffree); +} + +void +ffs_sb_swap(const struct fs *o, struct fs *n) +{ + size_t i; + const u_int32_t *o32; + u_int32_t *n32; + + /* + * In order to avoid a lot of lines, as the first N fields (52) + * of the superblock up to fs_fmod are u_int32_t, we just loop + * here to convert them. + */ + o32 = (const u_int32_t *)o; + n32 = (u_int32_t *)n; + for (i = 0; i < offsetof(struct fs, fs_fmod) / sizeof(u_int32_t); i++) + n32[i] = bswap32(o32[i]); + + n->fs_swuid = bswap64(o->fs_swuid); + n->fs_cgrotor = bswap32(o->fs_cgrotor); /* Unused */ + n->fs_old_cpc = bswap32(o->fs_old_cpc); + + /* These fields overlap with a possible location for the + * historic FS_DYNAMICPOSTBLFMT postbl table, and with the + * first half of the historic FS_42POSTBLFMT postbl table. + */ + n->fs_maxbsize = bswap32(o->fs_maxbsize); + /* XXX journal */ + n->fs_quota_magic = bswap32(o->fs_quota_magic); + for (i = 0; i < MAXQUOTAS; i++) + n->fs_quotafile[i] = bswap64(o->fs_quotafile[i]); + n->fs_sblockloc = bswap64(o->fs_sblockloc); + libsa_ffs_csumtotal_swap(&o->fs_cstotal, &n->fs_cstotal); + n->fs_time = bswap64(o->fs_time); + n->fs_size = bswap64(o->fs_size); + n->fs_dsize = bswap64(o->fs_dsize); + n->fs_csaddr = bswap64(o->fs_csaddr); + n->fs_pendingblocks = bswap64(o->fs_pendingblocks); + n->fs_pendinginodes = bswap32(o->fs_pendinginodes); + + /* These fields overlap with the second half of the + * historic FS_42POSTBLFMT postbl table + */ + for (i = 0; i < FSMAXSNAP; i++) + n->fs_snapinum[i] = bswap32(o->fs_snapinum[i]); + n->fs_avgfilesize = bswap32(o->fs_avgfilesize); + n->fs_avgfpdir = bswap32(o->fs_avgfpdir); + /* fs_sparecon[28] - ignore for now */ + n->fs_flags = bswap32(o->fs_flags); + n->fs_contigsumsize = bswap32(o->fs_contigsumsize); + n->fs_maxsymlinklen = bswap32(o->fs_maxsymlinklen); + n->fs_old_inodefmt = bswap32(o->fs_old_inodefmt); + n->fs_maxfilesize = bswap64(o->fs_maxfilesize); + n->fs_qbmask = bswap64(o->fs_qbmask); + n->fs_qfmask = bswap64(o->fs_qfmask); + n->fs_state = bswap32(o->fs_state); + n->fs_old_postblformat = bswap32(o->fs_old_postblformat); + n->fs_old_nrpos = bswap32(o->fs_old_nrpos); + n->fs_old_postbloff = bswap32(o->fs_old_postbloff); + n->fs_old_rotbloff = bswap32(o->fs_old_rotbloff); + + n->fs_magic = bswap32(o->fs_magic); +} + +void +ffs_dinode1_swap(struct ufs1_dinode *o, struct ufs1_dinode *n) +{ + size_t i; + + n->di_mode = bswap16(o->di_mode); + n->di_nlink = bswap16(o->di_nlink); + n->di_oldids[0] = bswap16(o->di_oldids[0]); + n->di_oldids[1] = bswap16(o->di_oldids[1]); + n->di_size = bswap64(o->di_size); + n->di_atime = bswap32(o->di_atime); + n->di_atimensec = bswap32(o->di_atimensec); + n->di_mtime = bswap32(o->di_mtime); + n->di_mtimensec = bswap32(o->di_mtimensec); + n->di_ctime = bswap32(o->di_ctime); + n->di_ctimensec = bswap32(o->di_ctimensec); + /* Swap these here, unlike kernel version .*/ + for (i = 0; i < UFS_NDADDR; i++) + n->di_db[i] = bswap32(o->di_db[i]); + for (i = 0; i < UFS_NIADDR; i++) + n->di_ib[i] = bswap32(o->di_ib[i]); + n->di_flags = bswap32(o->di_flags); + n->di_blocks = bswap32(o->di_blocks); + n->di_gen = bswap32(o->di_gen); + n->di_uid = bswap32(o->di_uid); + n->di_gid = bswap32(o->di_gid); +} + +void +ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n) +{ + size_t i; + + n->di_mode = bswap16(o->di_mode); + n->di_nlink = bswap16(o->di_nlink); + n->di_uid = bswap32(o->di_uid); + n->di_gid = bswap32(o->di_gid); + n->di_blksize = bswap32(o->di_blksize); + n->di_size = bswap64(o->di_size); + n->di_blocks = bswap64(o->di_blocks); + n->di_atime = bswap64(o->di_atime); + n->di_atimensec = bswap32(o->di_atimensec); + n->di_mtime = bswap64(o->di_mtime); + n->di_mtimensec = bswap32(o->di_mtimensec); + n->di_ctime = bswap64(o->di_ctime); + n->di_ctimensec = bswap32(o->di_ctimensec); + n->di_birthtime = bswap64(o->di_birthtime); + n->di_birthnsec = bswap32(o->di_birthnsec); + n->di_gen = bswap32(o->di_gen); + n->di_kernflags = bswap32(o->di_kernflags); + n->di_flags = bswap32(o->di_flags); + n->di_extsize = bswap32(o->di_extsize); + /* Swap these here, unlike kernel version .*/ + for (i = 0; i < UFS_NXADDR; i++) + n->di_extb[i] = bswap64(o->di_extb[i]); + for (i = 0; i < UFS_NDADDR; i++) + n->di_db[i] = bswap64(o->di_db[i]); + for (i = 0; i < UFS_NIADDR; i++) + n->di_ib[i] = bswap64(o->di_ib[i]); +} Index: sys/lib/libsa/ffsv1.c =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/ffsv1.c,v retrieving revision 1.7 diff -p -u -r1.7 ffsv1.c --- sys/lib/libsa/ffsv1.c 24 Jun 2019 13:58:24 -0000 1.7 +++ sys/lib/libsa/ffsv1.c 26 May 2021 09:59:27 -0000 @@ -13,8 +13,12 @@ #endif #define ufs_dinode ufs1_dinode +#define ufs_dinode_swap ffs_dinode1_swap +#define ufs_indp_swap bswap32 #define indp_t int32_t +#define FS_MAGIC FS_UFS1_MAGIC + #if 0 #define FSMOD "wapbl/ufs/ffs" #endif Index: sys/lib/libsa/ffsv2.c =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/ffsv2.c,v retrieving revision 1.7 diff -p -u -r1.7 ffsv2.c --- sys/lib/libsa/ffsv2.c 24 Jun 2019 13:58:24 -0000 1.7 +++ sys/lib/libsa/ffsv2.c 26 May 2021 09:59:27 -0000 @@ -13,8 +13,12 @@ #endif #define ufs_dinode ufs2_dinode +#define ufs_dinode_swap ffs_dinode2_swap +#define ufs_indp_swap bswap64 #define indp_t int64_t +#define FS_MAGIC FS_UFS2_MAGIC + #if 0 #define FSMOD "wapbl/ufs/ffs" #endif Index: sys/lib/libsa/lfsv1.c =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/lfsv1.c,v retrieving revision 1.14 diff -p -u -r1.14 lfsv1.c --- sys/lib/libsa/lfsv1.c 12 Aug 2015 18:28:01 -0000 1.14 +++ sys/lib/libsa/lfsv1.c 26 May 2021 09:59:27 -0000 @@ -25,6 +25,8 @@ #define dblksize(a, b, c) lfs_dblksize((a), (b), (c)) #define FSBTODB(fs, daddr) (daddr) /* LFSv1 uses sectors for addresses */ +#define FS_MAGIC LFS_MAGIC + #define FSMOD "lfs" #include "lib/libsa/ufs.c" Index: sys/lib/libsa/lfsv2.c =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/lfsv2.c,v retrieving revision 1.14 diff -p -u -r1.14 lfsv2.c --- sys/lib/libsa/lfsv2.c 12 Aug 2015 18:28:01 -0000 1.14 +++ sys/lib/libsa/lfsv2.c 26 May 2021 09:59:27 -0000 @@ -29,6 +29,8 @@ #define dblksize(a, b, c) lfs_dblksize((a), (b), (c)) #define FSBTODB(a, b) LFS_FSBTODB((a), (b)) +#define FS_MAGIC LFS_MAGIC + #define FSMOD "lfs" #include "lib/libsa/ufs.c" Index: sys/lib/libsa/ufs.c =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/ufs.c,v retrieving revision 1.79 diff -p -u -r1.79 ufs.c --- sys/lib/libsa/ufs.c 12 May 2021 08:45:28 -0000 1.79 +++ sys/lib/libsa/ufs.c 26 May 2021 09:59:27 -0000 @@ -100,6 +100,8 @@ #endif #ifdef LIBSA_LFS +/* Do not (yet) support FFS_EI on LFS. */ +#undef LIBSA_FFS_EI /* * In-core LFS superblock - just the on-disk one. */ @@ -124,13 +126,11 @@ typedef struct salfs FS; #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen #define lfs_version lfs_dlfs_u.u_32.dlfs_version -#define FS_MAGIC LFS_MAGIC #define SBLOCKSIZE LFS_SBPAD #define SBLOCKOFFSET LFS_LABELPAD #else /* NB ufs2 doesn't use the common superblock code... */ typedef struct fs FS; -#define FS_MAGIC FS_UFS1_MAGIC #define SBLOCKOFFSET SBLOCK_UFS1 #endif @@ -156,6 +156,9 @@ typedef uint32_t ino32_t; #ifndef FSBTODB #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp) #endif +#ifndef FS_MAGIC +#define FS_MAGIC FS_UFS1_MAGIC +#endif #ifndef UFS_NINDIR #define UFS_NINDIR FFS_NINDIR #endif @@ -165,6 +168,12 @@ typedef uint32_t ino32_t; #ifndef ufs_lblkno #define ufs_lblkno ffs_lblkno #endif +#ifndef ufs_dinode_swap +#define ufs_dinode_swap ffs_dinode1_swap +#endif +#ifndef ufs_indp_swap +#define ufs_indp_swap bswap32 +#endif /* * To avoid having a lot of filesystem-block sized buffers lurking (which @@ -192,6 +201,9 @@ struct file { char *f_buf; /* buffer for data block */ size_t f_buf_size; /* size of data block */ daddr_t f_buf_blkno; /* block number of data block */ +#if defined(LIBSA_FFS_EI) + bool f_swapped; /* FFS is other endian */ +#endif }; static int read_inode(ino32_t, struct open_file *); @@ -202,6 +214,52 @@ static int search_directory(const char * static void ffs_oldfscompat(FS *); #endif +static __inline__ bool +ffs_is_magic(FS *fs) +{ + return fs->fs_magic == FS_MAGIC; +} + +static __inline__ void +ffs_fix_magic_swapped(struct file *fp, FS *fs) +{ +#ifdef LIBSA_FFS_EI + fp->f_swapped = fs->fs_magic == bswap32(FS_MAGIC); + if (fp->f_swapped) +{ + ffs_sb_swap(fs, fs); +} +#endif +} + +#ifdef LIBSA_FFS_EI +static __inline__ bool +ffs_swapped(struct file *fp) +{ + return fp->f_swapped; +} +#endif + +static __inline__ uint16_t +ffs_get_reclen(struct file *fp, struct direct *dp) +{ +#ifdef LIBSA_FFS_EI + if (ffs_swapped(fp)) + return bswap16(dp->d_reclen); +#endif + return dp->d_reclen; +} + +static __inline__ uint32_t +ffs_get_ino(struct file *fp, struct direct *dp) +{ +#ifdef LIBSA_FFS_EI + if (ffs_swapped(fp)) + return bswap32(dp->d_ino); +#endif + return dp->d_ino; +} + #ifdef LIBSA_LFS /* @@ -291,6 +349,10 @@ read_inode(ino32_t inumber, struct open_ fp->f_di = *dip; #else fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)]; +#ifdef LIBSA_FFS_EI + if (ffs_swapped(fp)) + ufs_dinode_swap(&fp->f_di, &fp->f_di); +#endif #endif /* @@ -387,15 +449,30 @@ block_map(struct open_file *f, indp_t fi return rc; if (rsize != (size_t)fs->fs_bsize) return EIO; - ind_block_num = buf[file_block >> level]; +#ifdef LIBSA_FFS_EI + if (ffs_swapped(fp)) + ind_block_num = ufs_indp_swap(buf[file_block >> level]); + else +#endif + ind_block_num = buf[file_block >> level]; if (level == 0) break; file_block &= (1 << level) - 1; } /* Save the part of the block that contains this sector */ - memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], - IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); +#if defined(LIBSA_FFS_EI) + if (ffs_swapped(fp)) { + size_t i; + + for (i = 0; i < IND_CACHE_SZ; i++) { + fp->f_ind_cache[i] = ufs_indp_swap( + buf[(file_block & ~IND_CACHE_MASK) + i]); + } + } else +#endif + memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], + IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); fp->f_ind_cache_block = ind_cache; *disk_block_p = ind_block_num; @@ -487,10 +564,11 @@ search_directory(const char *name, int l dp = (struct direct *)buf; edp = (struct direct *)(buf + buf_size); - for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) { - if (dp->d_reclen <= 0) + for (; dp < edp; + dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) { + if (ffs_get_reclen(fp, dp) <= 0) break; - if (dp->d_ino == (ino32_t)0) + if (ffs_get_ino(fp, dp) == (ino32_t)0) continue; #if BYTE_ORDER == LITTLE_ENDIAN if (fp->f_fs->fs_maxsymlinklen <= 0) @@ -501,7 +579,7 @@ search_directory(const char *name, int l if (namlen == length && !memcmp(name, dp->d_name, length)) { /* found entry */ - *inumber_p = dp->d_ino; + *inumber_p = ffs_get_ino(fp, dp); return 0; } } @@ -513,6 +591,7 @@ search_directory(const char *name, int l static __inline__ int ffs_find_superblock(struct open_file *f, FS *fs) { + struct file *fp = (struct file *)f->f_fsdata; int rc; size_t buf_size; #ifdef LIBSA_FFSv2 @@ -522,14 +601,16 @@ ffs_find_superblock(struct open_file *f, for (i = 0; sblock_try[i] != -1; i++) { rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); - if (rc != 0 || buf_size != SBLOCKSIZE) + if (rc) return rc; + if (buf_size != SBLOCKSIZE) + return EINVAL; + ffs_fix_magic_swapped(fp, fs); if (fs->fs_sblockloc != sblock_try[i]) /* an alternate superblock - try again */ continue; - if (fs->fs_magic == FS_UFS2_MAGIC) { + if (ffs_is_magic(fs)) return 0; - } } return EINVAL; #else /* LIBSA_FFSv2 */ @@ -537,12 +618,17 @@ ffs_find_superblock(struct open_file *f, SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size); if (rc) return rc; - if (buf_size != SBLOCKSIZE || + if (buf_size != SBLOCKSIZE) + return EINVAL; + ffs_fix_magic_swapped(fp, fs); + #ifdef LIBSA_LFS - fs->lfs_version != REQUIRED_LFS_VERSION || + if (fs->lfs_version != REQUIRED_LFS_VERSION) + return EINVAL; #endif - fs->fs_magic != FS_MAGIC) + if (!ffs_is_magic(fs)) return EINVAL; + return 0; #endif /* !LIBSA_FFSv2 */ } @@ -915,9 +1001,10 @@ ufs_ls(struct open_file *f, const char * dp = (struct direct *)buf; edp = (struct direct *)(buf + buf_size); - for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) { + for (; dp < edp; + dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) { const char *t; - if (dp->d_ino == 0) + if (ffs_get_ino(fp, dp) == 0) continue; if (dp->d_type >= NELEM(typestr) || @@ -936,7 +1023,7 @@ ufs_ls(struct open_file *f, const char * goto out; } lsadd(&names, pattern, dp->d_name, strlen(dp->d_name), - dp->d_ino, t); + ffs_get_ino(fp, dp), t); } fp->f_seekp += buf_size; } Index: sys/lib/libsa/ufs.h =================================================================== RCS file: /cvsroot/src/sys/lib/libsa/ufs.h,v retrieving revision 1.10 diff -p -u -r1.10 ufs.h --- sys/lib/libsa/ufs.h 25 Dec 2011 06:09:08 -0000 1.10 +++ sys/lib/libsa/ufs.h 26 May 2021 09:59:27 -0000 @@ -34,3 +34,11 @@ FS_DEF(ufs); FS_DEF(ffsv1); FS_DEF(ffsv2); + +/* in libsa's ffs_bswap.c */ +struct fs; +struct ufs1_dinode; +struct ufs2_dinode; +void ffs_sb_swap(const struct fs *, struct fs *); +void ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *); +void ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *);