From nobody Mon Apr 29 08:09:50 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1488856487501984.2105820079582; Mon, 6 Mar 2017 19:14:47 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 7C5958035A; Mon, 6 Mar 2017 19:14:39 -0800 (PST) Received: from mail-qk0-x241.google.com (mail-qk0-x241.google.com [IPv6:2607:f8b0:400d:c09::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 85F7A80347 for ; Mon, 6 Mar 2017 19:14:37 -0800 (PST) Received: by mail-qk0-x241.google.com with SMTP id n141so25731592qke.3 for ; Mon, 06 Mar 2017 19:14:37 -0800 (PST) Received: from foober.ini.cmu.edu (pool-108-39-248-175.pitbpa.fios.verizon.net. [108.39.248.175]) by smtp.gmail.com with ESMTPSA id v26sm2901013qtc.13.2017.03.06.19.14.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 19:14:32 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=G+VhkDP5RQb0FO+azj/s8HxSGYT78eMMe/d+rLp9n20=; b=D3YB+OnmGlNUIiQZrnHHr+5VwmRY4KSR6ERPZUKR4rbFJR05rEHvS0HQBEJFNYQKVZ QZVybSSupzthP8cU4+vZnha5x1fQGP+NnxO6+EZCeAk56nt9YQt0lVSl7Ug3XZ9ARtN9 AnvYA4O8LVbIV6Bz7nfkcsc1ylGr3aHjevUOjs5xq/TwSISy2rp15WStywvmVNZwdWXn Lz35YJLXF+KxsIhK/Nt5cI2RoJeb4uEPI/TK18u4KOyEVa9XlIEYYrmiJnW9+nNuA378 WLu4L81fA5EUIWFpWaO5UdRYzw/lwanYI6JjgS0GKeDK3NScG3A8lp5Romegn2rF25DK npew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=G+VhkDP5RQb0FO+azj/s8HxSGYT78eMMe/d+rLp9n20=; b=DpWnmRSaqZVf1bVw6ZoFAEtU8MUwemJE1T/SvPxMpPbqTqBzsc0vt+YM+eMANNbAbH 9wtC4xSCL+AX6iu/v/By7oBi5jcCEc2dhb6rS3HKn/GOgRZ1koEsC/cyoRXOxWr4x9yj gwEC07QWkRXXgF09LtPWua55O7M2YJgKSwAbUOtAzpHukr3w4k0+GqSMNbmWEOJ7O971 lV1fGsfjQ2S6Sf2uGpaK/kqwUUzBb89nvuJDV0w1oX9b5uoSbhdQEK1BIk61m+OWYKNW 6mpOlnsstu3L/32AebHrmVqGAsl6+Rm/+ATaFNKUcVyZr3WcVfOsMmKmTGACpXv7/z4e AOpw== X-Gm-Message-State: AMke39nOFLTouVPUAt2QnerFQwAVdCOmAIo+2vp1F5Bvvj44AbvKuERUTyHeT9YOFac/mA== X-Received: by 10.237.43.68 with SMTP id p62mr19032279qtd.207.1488856473100; Mon, 06 Mar 2017 19:14:33 -0800 (PST) From: "Gabriel L. Somlo" To: edk2-devel@ml01.01.org Date: Mon, 6 Mar 2017 22:14:20 -0500 Message-Id: <1488856465-8965-2-git-send-email-gsomlo@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> References: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> Subject: [edk2] [RFC PATCH 1/6] FswHfsPlus: add File System Wrapper (FSW) interface code X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jordan.l.justen@intel.com, lersek@redhat.com, agraf@suse.de MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" All files are licensed under BSD. All files are copyright Christoph Pfisterer (from refit 0.14), with the exception of "fsw_efi_edk2_base.h", which is copyright Stefan Agner (from the refind project). This patch imports the completely unmodified original files. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Gabriel Somlo --- OvmfPkg/FswHfsPlus/fsw_base.h | 158 +++++ OvmfPkg/FswHfsPlus/fsw_core.c | 929 ++++++++++++++++++++++++++++ OvmfPkg/FswHfsPlus/fsw_core.h | 517 ++++++++++++++++ OvmfPkg/FswHfsPlus/fsw_efi.c | 1044 ++++++++++++++++++++++++++++= ++++ OvmfPkg/FswHfsPlus/fsw_efi.h | 102 ++++ OvmfPkg/FswHfsPlus/fsw_efi_base.h | 82 +++ OvmfPkg/FswHfsPlus/fsw_efi_edk2_base.h | 76 +++ OvmfPkg/FswHfsPlus/fsw_efi_lib.c | 129 ++++ OvmfPkg/FswHfsPlus/fsw_lib.c | 294 +++++++++ OvmfPkg/FswHfsPlus/fsw_strfunc.h | 453 ++++++++++++++ 10 files changed, 3784 insertions(+) create mode 100644 OvmfPkg/FswHfsPlus/fsw_base.h create mode 100644 OvmfPkg/FswHfsPlus/fsw_core.c create mode 100644 OvmfPkg/FswHfsPlus/fsw_core.h create mode 100644 OvmfPkg/FswHfsPlus/fsw_efi.c create mode 100644 OvmfPkg/FswHfsPlus/fsw_efi.h create mode 100644 OvmfPkg/FswHfsPlus/fsw_efi_base.h create mode 100644 OvmfPkg/FswHfsPlus/fsw_efi_edk2_base.h create mode 100644 OvmfPkg/FswHfsPlus/fsw_efi_lib.c create mode 100644 OvmfPkg/FswHfsPlus/fsw_lib.c create mode 100644 OvmfPkg/FswHfsPlus/fsw_strfunc.h diff --git a/OvmfPkg/FswHfsPlus/fsw_base.h b/OvmfPkg/FswHfsPlus/fsw_base.h new file mode 100644 index 0000000..ab18385 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_base.h @@ -0,0 +1,158 @@ +/** + * \file fsw_base.h + * Base definitions switch. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#ifndef _FSW_BASE_H_ +#define _FSW_BASE_H_ + + +#ifndef FSW_DEBUG_LEVEL +/** + * Global debugging level. Can be set locally for the scope of a single + * file by defining the macro before fsw_base.h is included. + */ +#define FSW_DEBUG_LEVEL 1 +#endif + + +#ifdef HOST_EFI +#include "fsw_efi_base.h" +#endif + +#ifdef HOST_POSIX +#include "fsw_posix_base.h" +#endif + +// message printing + +#if FSW_DEBUG_LEVEL >=3D 1 +#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params +#else +#define FSW_MSG_ASSERT(params) +#endif + +#if FSW_DEBUG_LEVEL >=3D 2 +#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params +#else +#define FSW_MSG_DEBUG(params) +#endif + +#if FSW_DEBUG_LEVEL >=3D 3 +#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params +#else +#define FSW_MSG_DEBUGV(params) +#endif + + +// Documentation for system-dependent defines + +/** + * \typedef fsw_s8 + * Signed 8-bit integer. + */ + +/** + * \typedef fsw_u8 + * Unsigned 8-bit integer. + */ + +/** + * \typedef fsw_s16 + * Signed 16-bit integer. + */ + +/** + * \typedef fsw_u16 + * Unsigned 16-bit integer. + */ + +/** + * \typedef fsw_s32 + * Signed 32-bit integer. + */ + +/** + * \typedef fsw_u32 + * Unsigned 32-bit integer. + */ + +/** + * \typedef fsw_s64 + * Signed 64-bit integer. + */ + +/** + * \typedef fsw_u64 + * Unsigned 64-bit integer. + */ + + +/** + * \def fsw_alloc(size,ptrptr) + * Allocate memory on the heap. This function or macro allocates \a size + * bytes of memory using host-specific methods. The address of the + * allocated memory block is stored into the pointer variable pointed + * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block + * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory + * to allocated the requested block. + */ + +/** + * \def fsw_free(ptr) + * Release allocated memory. This function or macro returns an allocated + * memory block to the heap for reuse. Does not return a status. + */ + +/** + * \def fsw_memcpy(dest,src,size) + * Copies a block of memory from \a src to \a dest. The two memory blocks + * must not overlap, or the result of the operation will be undefined. + * Does not return a status. + */ + +/** + * \def fsw_memeq(dest,src,size) + * Compares two blocks of memory for equality. Returns boolean true if the + * memory blocks are equal, boolean false if they are different. + */ + +/** + * \def fsw_memzero(dest,size) + * Initializes a block of memory with zeros. Does not return a status. + */ + + +#endif diff --git a/OvmfPkg/FswHfsPlus/fsw_core.c b/OvmfPkg/FswHfsPlus/fsw_core.c new file mode 100644 index 0000000..db7016b --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_core.c @@ -0,0 +1,929 @@ +/** + * \file fsw_core.c + * Core file system wrapper abstraction layer code. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#include "fsw_core.h" + + +// functions + +static void fsw_blockcache_free(struct fsw_volume *vol); + +#define MAX_CACHE_LEVEL (5) + + +/** + * Mount a volume with a given file system driver. This function is called= by the + * host driver to make a volume accessible. The file system driver to use = is specified + * by a pointer to its dispatch table. The file system driver will look at= the + * data on the volume to determine if it can read the format. If the volum= e is found + * unsuitable, FSW_UNSUPPORTED is returned. + * + * If this function returns FSW_SUCCESS, *vol_out points at a valid volume= data + * structure. The caller must release it later by calling fsw_unmount. + * + * If this function returns an error status, the caller only needs to clea= n up its + * own buffers that may have been allocated through the read_block interfa= ce. + */ + +fsw_status_t fsw_mount(void *host_data, + struct fsw_host_table *host_table, + struct fsw_fstype_table *fstype_table, + struct fsw_volume **vol_out) +{ + fsw_status_t status; + struct fsw_volume *vol; + =20 + // allocate memory for the structure + status =3D fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&= vol); + if (status) + return status; + =20 + // initialize fields + vol->phys_blocksize =3D 512; + vol->log_blocksize =3D 512; + vol->label.type =3D FSW_STRING_TYPE_EMPTY; + vol->host_data =3D host_data; + vol->host_table =3D host_table; + vol->fstype_table =3D fstype_table; + vol->host_string_type =3D host_table->native_string_type; + =20 + // let the fs driver mount the file system + status =3D vol->fstype_table->volume_mount(vol); + if (status) + goto errorexit; + =20 + // TODO: anything else? + =20 + *vol_out =3D vol; + return FSW_SUCCESS; + =20 +errorexit: + fsw_unmount(vol); + return status; +} + +/** + * Unmount a volume by releasing all memory associated with it. This funct= ion is + * called by the host driver when a volume is no longer needed. It is also= called + * by the core after a failed mount to clean up any allocated memory. + * + * Note that all dnodes must have been released before calling this functi= on. + */ + +void fsw_unmount(struct fsw_volume *vol) +{ + if (vol->root) + fsw_dnode_release(vol->root); + // TODO: check that no other dnodes are still around + =20 + vol->fstype_table->volume_free(vol); + =20 + fsw_blockcache_free(vol); + fsw_strfree(&vol->label); + fsw_free(vol); +} + +/** + * Get in-depth information on the volume. This function can be called by = the host + * driver to get additional information on the volume. + */ + +fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_sta= t *sb) +{ + return vol->fstype_table->volume_stat(vol, sb); +} + +/** + * Set the physical and logical block sizes of the volume. This functions = is called by + * the file system driver to announce the block sizes it wants to use for = accessing + * the disk (physical) and for addressing file contents (logical). + * Usually both sizes will be the same but there may be file systems that = need to access + * metadata at a smaller block size than the allocation unit for files. + * + * Calling this function causes the block cache to be dropped. All pointer= s returned + * from fsw_block_get become invalid. This function should only be called = while + * mounting the file system, not as a part of file access operations. + * + * Both sizes are measured in bytes, must be powers of 2, and must not be = smaller + * than 512 bytes. The logical block size cannot be smaller than the physi= cal block size. + */ + +void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw= _u32 log_blocksize) +{ + // TODO: Check the sizes. Both must be powers of 2. log_blocksize must= not be smaller than + // phys_blocksize. + =20 + // drop core block cache if present + fsw_blockcache_free(vol); + =20 + // signal host driver to drop caches etc. + vol->host_table->change_blocksize(vol, + vol->phys_blocksize, vol->log_blocks= ize, + phys_blocksize, log_blocksize); + =20 + vol->phys_blocksize =3D phys_blocksize; + vol->log_blocksize =3D log_blocksize; +} + +/** + * Get a block of data from the disk. This function is called by the file = system driver + * or by core functions. It calls through to the host driver's device acce= ss routine. + * Given a physical block number, it reads the block into memory (or fetch= es it from the + * block cache) and returns the address of the memory buffer. The caller s= hould provide + * an indication of how important the block is in the cache_level paramete= r. Blocks with + * a low level are purged first. Some suggestions for cache levels: + * + * - 0: File data + * - 1: Directory data, symlink data + * - 2: File system metadata + * - 3..5: File system metadata with a high rate of access + * + * If this function returns successfully, the returned data pointer is val= id until the + * caller calls fsw_block_release. + */ + +fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fs= w_u32 cache_level, void **buffer_out) +{ + fsw_status_t status; + fsw_u32 i, discard_level, new_bcache_size; + struct fsw_blockcache *new_bcache; + =20 + // TODO: allow the host driver to do its own caching; just call throug= h if + // the appropriate function pointers are set + =20 + if (cache_level > MAX_CACHE_LEVEL) + cache_level =3D MAX_CACHE_LEVEL; + =20 + // check block cache + for (i =3D 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].phys_bno =3D=3D phys_bno) { + // cache hit! + if (vol->bcache[i].cache_level < cache_level) + vol->bcache[i].cache_level =3D cache_level; // promote th= e entry + vol->bcache[i].refcount++; + *buffer_out =3D vol->bcache[i].data; + return FSW_SUCCESS; + } + } + =20 + // find a free entry in the cache table + for (i =3D 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].phys_bno =3D=3D FSW_INVALID_BNO) + break; + } + if (i >=3D vol->bcache_size) { + for (discard_level =3D 0; discard_level <=3D MAX_CACHE_LEVEL; disc= ard_level++) { + for (i =3D 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].refcount =3D=3D 0 && vol->bcache[i].cac= he_level <=3D discard_level) + break; + } + if (i < vol->bcache_size) + break; + } + } + if (i >=3D vol->bcache_size) { + // enlarge / create the cache + if (vol->bcache_size < 16) + new_bcache_size =3D 16; + else + new_bcache_size =3D vol->bcache_size << 1; + status =3D fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcach= e), &new_bcache); + if (status) + return status; + if (vol->bcache_size > 0) + fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(= struct fsw_blockcache)); + for (i =3D vol->bcache_size; i < new_bcache_size; i++) { + new_bcache[i].refcount =3D 0; + new_bcache[i].cache_level =3D 0; + new_bcache[i].phys_bno =3D FSW_INVALID_BNO; + new_bcache[i].data =3D NULL; + } + i =3D vol->bcache_size; + =20 + // switch caches + if (vol->bcache !=3D NULL) + fsw_free(vol->bcache); + vol->bcache =3D new_bcache; + vol->bcache_size =3D new_bcache_size; + } + vol->bcache[i].phys_bno =3D FSW_INVALID_BNO; + =20 + // read the data + if (vol->bcache[i].data =3D=3D NULL) { + status =3D fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data); + if (status) + return status; + } + status =3D vol->host_table->read_block(vol, phys_bno, vol->bcache[i].d= ata); + if (status) + return status; + =20 + vol->bcache[i].phys_bno =3D phys_bno; + vol->bcache[i].cache_level =3D cache_level; + vol->bcache[i].refcount =3D 1; + *buffer_out =3D vol->bcache[i].data; + return FSW_SUCCESS; +} + +/** + * Releases a disk block. This function must be called to release disk blo= cks returned + * from fsw_block_get. + */ + +void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *= buffer) +{ + fsw_u32 i; + =20 + // TODO: allow the host driver to do its own caching; just call throug= h if + // the appropriate function pointers are set + =20 + // update block cache + for (i =3D 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].phys_bno =3D=3D phys_bno && vol->bcache[i].refc= ount > 0) + vol->bcache[i].refcount--; + } +} + +/** + * Release the block cache. Called internally when changing block sizes an= d when + * unmounting the volume. It frees all data occupied by the generic block = cache. + */ + +static void fsw_blockcache_free(struct fsw_volume *vol) +{ + fsw_u32 i; + =20 + for (i =3D 0; i < vol->bcache_size; i++) { + if (vol->bcache[i].data !=3D NULL) + fsw_free(vol->bcache[i].data); + } + if (vol->bcache !=3D NULL) { + fsw_free(vol->bcache); + vol->bcache =3D NULL; + } + vol->bcache_size =3D 0; +} + +/** + * Add a new dnode to the list of known dnodes. This internal function is = used when a + * dnode is created to add it to the dnode list that is used to search for= existing + * dnodes by id. + */ + +static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *d= no) +{ + dno->next =3D vol->dnode_head; + if (vol->dnode_head !=3D NULL) + vol->dnode_head->prev =3D dno; + dno->prev =3D NULL; + vol->dnode_head =3D dno; +} + +/** + * Create a dnode representing the root directory. This function is called= by the file system + * driver while mounting the file system. The root directory is special be= cause it has no parent + * dnode, its name is defined to be empty, and its type is also fixed. Oth= erwise, this functions + * behaves in the same way as fsw_dnode_create. + */ + +fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u32 dnode_i= d, struct fsw_dnode **dno_out) +{ + fsw_status_t status; + struct fsw_dnode *dno; + =20 + // allocate memory for the structure + status =3D fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void = **)&dno); + if (status) + return status; + =20 + // fill the structure + dno->vol =3D vol; + dno->parent =3D NULL; + dno->dnode_id =3D dnode_id; + dno->type =3D FSW_DNODE_TYPE_DIR; + dno->refcount =3D 1; + dno->name.type =3D FSW_STRING_TYPE_EMPTY; + // TODO: instead, call a function to create an empty string in the nat= ive string type + =20 + fsw_dnode_register(vol, dno); + =20 + *dno_out =3D dno; + return FSW_SUCCESS; +} + +/** + * Create a new dnode representing a file system object. This function is = called by + * the file system driver in response to directory lookup or read requests= . Note that + * if there already is a dnode with the given dnode_id on record, then no = new object + * is created. Instead, the existing dnode is returned and its reference c= ount + * increased. All other parameters are ignored in this case. + * + * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is= sufficient + * to fill the type field during the dnode_fill call. + * + * The name parameter must describe a string with the object's name. A cop= y will be + * stored in the dnode structure for future reference. The name will not b= e used to + * shortcut directory lookups, but may be used to reconstruct paths. + * + * If the function returns successfully, *dno_out contains a pointer to th= e dnode + * that must be released by the caller with fsw_dnode_release. + */ + +fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u32 dnode_= id, int type, + struct fsw_string *name, struct fsw_dnode **= dno_out) +{ + fsw_status_t status; + struct fsw_volume *vol =3D parent_dno->vol; + struct fsw_dnode *dno; + =20 + // check if we already have a dnode with the same id + for (dno =3D vol->dnode_head; dno; dno =3D dno->next) { + if (dno->dnode_id =3D=3D dnode_id) { + fsw_dnode_retain(dno); + *dno_out =3D dno; + return FSW_SUCCESS; + } + } + =20 + // allocate memory for the structure + status =3D fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void = **)&dno); + if (status) + return status; + =20 + // fill the structure + dno->vol =3D vol; + dno->parent =3D parent_dno; + fsw_dnode_retain(dno->parent); + dno->dnode_id =3D dnode_id; + dno->type =3D type; + dno->refcount =3D 1; + status =3D fsw_strdup_coerce(&dno->name, vol->host_table->native_strin= g_type, name); + if (status) { + fsw_free(dno); + return status; + } + =20 + fsw_dnode_register(vol, dno); + =20 + *dno_out =3D dno; + return FSW_SUCCESS; +} + +/** + * Increases the reference count of a dnode. This must be balanced with + * fsw_dnode_release calls. Note that some dnode functions return a retain= ed + * dnode pointer to their caller. + */ + +void fsw_dnode_retain(struct fsw_dnode *dno) +{ + dno->refcount++; +} + +/** + * Release a dnode pointer, deallocating it if this was the last reference. + * This function decrements the reference counter of the dnode. If the cou= nter + * reaches zero, the dnode is freed. Since the parent dnode is released + * during that process, this function may cause it to be freed, too. + */ + +void fsw_dnode_release(struct fsw_dnode *dno) +{ + struct fsw_volume *vol =3D dno->vol; + struct fsw_dnode *parent_dno; + =20 + dno->refcount--; + =20 + if (dno->refcount =3D=3D 0) { + parent_dno =3D dno->parent; + =20 + // de-register from volume's list + if (dno->next) + dno->next->prev =3D dno->prev; + if (dno->prev) + dno->prev->next =3D dno->next; + if (vol->dnode_head =3D=3D dno) + vol->dnode_head =3D dno->next; + =20 + // run fstype-specific cleanup + vol->fstype_table->dnode_free(vol, dno); + =20 + fsw_strfree(&dno->name); + fsw_free(dno); + =20 + // release our pointer to the parent, possibly deallocating it, too + if (parent_dno) + fsw_dnode_release(parent_dno); + } +} + +/** + * Get full information about a dnode from disk. This function is called b= y the host + * driver as well as by the core functions. Some file systems defer readin= g full + * information on a dnode until it is actually needed (i.e. separation bet= ween + * directory and inode information). This function makes sure that all inf= ormation + * is available in the dnode structure. The following fields may not have = a correct + * value until fsw_dnode_fill has been called: + * + * type, size + */ + +fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno) +{ + // TODO: check a flag right here, call fstype's dnode_fill only once p= er dnode + =20 + return dno->vol->fstype_table->dnode_fill(dno->vol, dno); +} + +/** + * Get extended information about a dnode. This function can be called by = the host + * driver to get a full compliment of information about a dnode in additio= n to the + * fields of the fsw_dnode structure itself. + * + * Some data requires host-specific conversion to be useful (i.e. timestam= ps) and + * will be passed to callback functions instead of being written into the = structure. + * These callbacks must be filled in by the caller. + */ + +fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *= sb) +{ + fsw_status_t status; + =20 + status =3D fsw_dnode_fill(dno); + if (status) + return status; + =20 + sb->used_bytes =3D 0; + status =3D dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb); + if (!status && !sb->used_bytes) + sb->used_bytes =3D DivU64x32(dno->size + dno->vol->log_blocksize -= 1, dno->vol->log_blocksize, NULL); + return status; +} + +/** + * Lookup a directory entry by name. This function is called by the host d= river. + * Given a directory dnode and a file name, it looks up the named entry in= the + * directory. + * + * If the dnode is not a directory, the call will fail. The caller is resp= onsible for + * resolving symbolic links before calling this function. + * + * If the function returns FSW_SUCCESS, *child_dno_out points to the reque= sted directory + * entry. The caller must call fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno, + struct fsw_string *lookup_name, struct fsw_d= node **child_dno_out) +{ + fsw_status_t status; + =20 + status =3D fsw_dnode_fill(dno); + if (status) + return status; + if (dno->type !=3D FSW_DNODE_TYPE_DIR) + return FSW_UNSUPPORTED; + =20 + return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, = child_dno_out); +} + +/** + * Find a file system object by path. This function is called by the host = driver. + * Given a directory dnode and a relative or absolute path, it walks the d= irectory + * tree until it finds the target dnode. If an intermediate node turns out= to be + * a symlink, it is resolved automatically. If the target node is a symlin= k, it + * is not resolved. + * + * If the function returns FSW_SUCCESS, *child_dno_out points to the reque= sted directory + * entry. The caller must call fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno, + struct fsw_string *lookup_path, char se= parator, + struct fsw_dnode **child_dno_out) +{ + fsw_status_t status; + struct fsw_volume *vol =3D dno->vol; + struct fsw_dnode *child_dno =3D NULL; + struct fsw_string lookup_name; + struct fsw_string remaining_path; + int root_if_empty; + =20 + remaining_path =3D *lookup_path; + fsw_dnode_retain(dno); + =20 + // loop over the path + for (root_if_empty =3D 1; fsw_strlen(&remaining_path) > 0; root_if_emp= ty =3D 0) { + // parse next path component + fsw_strsplit(&lookup_name, &remaining_path, separator); + =20 + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%= s' and %d '%s'\n"), + lookup_name.len, lookup_name.data, + remaining_path.len, remaining_path.data)); + =20 + if (fsw_strlen(&lookup_name) =3D=3D 0) { // empty path comp= onent + if (root_if_empty) + child_dno =3D vol->root; + else + child_dno =3D dno; + fsw_dnode_retain(child_dno); + =20 + } else { + // do an actual directory lookup + =20 + // ensure we have full information + status =3D fsw_dnode_fill(dno); + if (status) + goto errorexit; + =20 + // resolve symlink if necessary + if (dno->type =3D=3D FSW_DNODE_TYPE_SYMLINK) { + status =3D fsw_dnode_resolve(dno, &child_dno); + if (status) + goto errorexit; + =20 + // symlink target becomes the new dno + fsw_dnode_release(dno); + dno =3D child_dno; // is already retained + child_dno =3D NULL; + =20 + // ensure we have full information + status =3D fsw_dnode_fill(dno); + if (status) + goto errorexit; + } + =20 + // make sure we operate on a directory + if (dno->type !=3D FSW_DNODE_TYPE_DIR) { + return FSW_UNSUPPORTED; + goto errorexit; + } + =20 + // check special paths + if (fsw_streq_cstr(&lookup_name, ".")) { // self directory + child_dno =3D dno; + fsw_dnode_retain(child_dno); + =20 + } else if (fsw_streq_cstr(&lookup_name, "..")) { // parent d= irectory + if (dno->parent =3D=3D NULL) { + // We cannot go up from the root directory. Caution: C= ertain apps like the EFI shell + // rely on this behaviour! + status =3D FSW_NOT_FOUND; + goto errorexit; + } + child_dno =3D dno->parent; + fsw_dnode_retain(child_dno); + =20 + } else { + // do an actual lookup + status =3D vol->fstype_table->dir_lookup(vol, dno, &lookup= _name, &child_dno); + if (status) + goto errorexit; + } + } + =20 + // child_dno becomes the new dno + fsw_dnode_release(dno); + dno =3D child_dno; // is already retained + child_dno =3D NULL; + =20 + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\= n"), dno->dnode_id)); + } + =20 + *child_dno_out =3D dno; + return FSW_SUCCESS; + =20 +errorexit: + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %= d\n"), status)); + fsw_dnode_release(dno); + if (child_dno !=3D NULL) + fsw_dnode_release(child_dno); + return status; +} + +/** + * Get the next directory item in sequential order. This function is calle= d by the + * host driver to read the complete contents of a directory in sequential = (file system + * defined) order. Calling this function returns the next entry. Iteration= state is + * kept by a shandle on the directory's dnode. The caller must set up the = shandle + * when starting the iteration. + * + * When the end of the directory is reached, this function returns FSW_NOT= _FOUND. + * If the function returns FSW_SUCCESS, *child_dno_out points to the next = directory + * entry. The caller must call fsw_dnode_release on it. + */ + +fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnod= e **child_dno_out) +{ + fsw_status_t status; + struct fsw_dnode *dno =3D shand->dnode; + fsw_u64 saved_pos; + =20 + if (dno->type !=3D FSW_DNODE_TYPE_DIR) + return FSW_UNSUPPORTED; + =20 + saved_pos =3D shand->pos; + status =3D dno->vol->fstype_table->dir_read(dno->vol, dno, shand, chil= d_dno_out); + if (status) + shand->pos =3D saved_pos; + return status; +} + +/** + * Read the target path of a symbolic link. This function is called by the= host driver + * to read the "content" of a symbolic link, that is the relative or absol= ute path + * it points to. + * + * If the function returns FSW_SUCCESS, the string handle provided by the = caller is + * filled with a string in the host's preferred encoding. The caller is re= sponsible + * for calling fsw_strfree on the string. + */ + +fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *= target_name) +{ + fsw_status_t status; + =20 + status =3D fsw_dnode_fill(dno); + if (status) + return status; + if (dno->type !=3D FSW_DNODE_TYPE_SYMLINK) + return FSW_UNSUPPORTED; + =20 + return dno->vol->fstype_table->readlink(dno->vol, dno, target_name); +} + +/** + * Read the target path of a symbolic link by accessing file data. This fu= nction can + * be called by the file system driver if the file system stores the targe= t path + * as normal file data. This function will open an shandle, read the whole= content + * of the file into a buffer, and build a string from that. Currently the = encoding + * for the string is fixed as FSW_STRING_TYPE_ISO88591. + * + * If the function returns FSW_SUCCESS, the string handle provided by the = caller is + * filled with a string in the host's preferred encoding. The caller is re= sponsible + * for calling fsw_strfree on the string. + */ + +fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_str= ing *link_target) +{ + fsw_status_t status; + struct fsw_shandle shand; + fsw_u32 buffer_size; + char buffer[FSW_PATH_MAX]; + struct fsw_string s; + =20 + if (dno->size > FSW_PATH_MAX) + return FSW_VOLUME_CORRUPTED; + =20 + s.type =3D FSW_STRING_TYPE_ISO88591; + s.size =3D s.len =3D (int)dno->size; + s.data =3D buffer; + =20 + // open shandle and read the data + status =3D fsw_shandle_open(dno, &shand); + if (status) + return status; + buffer_size =3D (fsw_u32)s.size; + status =3D fsw_shandle_read(&shand, &buffer_size, buffer); + fsw_shandle_close(&shand); + if (status) + return status; + if ((int)buffer_size < s.size) + return FSW_VOLUME_CORRUPTED; + =20 + status =3D fsw_strdup_coerce(link_target, dno->vol->host_string_type, = &s); + return status; +} + +/** + * Resolve a symbolic link. This function can be called by the host driver= to make + * sure the a dnode is fully resolved instead of pointing at a symlink. If= the dnode + * passed in is not a symlink, it is returned unmodified. + * + * Note that absolute paths will be resolved relative to the root director= y of the + * volume. If the host is an operating system with its own VFS layer, it s= hould + * resolve symlinks on its own. + * + * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode = that is + * not a symlink. The caller is responsible for calling fsw_dnode_release = on it. + */ + +fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **t= arget_dno_out) +{ + fsw_status_t status; + struct fsw_string target_name; + struct fsw_dnode *target_dno; + =20 + fsw_dnode_retain(dno); + =20 + while (1) { + // get full information + status =3D fsw_dnode_fill(dno); + if (status) + goto errorexit; + if (dno->type !=3D FSW_DNODE_TYPE_SYMLINK) { + // found a non-symlink target, return it + *target_dno_out =3D dno; + return FSW_SUCCESS; + } + if (dno->parent =3D=3D NULL) { // safety measure, cannot happen= in theory + status =3D FSW_NOT_FOUND; + goto errorexit; + } + =20 + // read the link's target + status =3D fsw_dnode_readlink(dno, &target_name); + if (status) + goto errorexit; + =20 + // resolve it + status =3D fsw_dnode_lookup_path(dno->parent, &target_name, '/', &= target_dno); + fsw_strfree(&target_name); + if (status) + goto errorexit; + =20 + // target_dno becomes the new dno + fsw_dnode_release(dno); + dno =3D target_dno; // is already retained + } + =20 +errorexit: + fsw_dnode_release(dno); + return status; +} + +/** + * Set up a shandle (storage handle) to access a file's data. This functio= n is called + * by the host driver and by the core when they need to access a file's da= ta. It is also + * used in accessing the raw data of directories and symlinks if the file = system uses + * the same mechanisms for storing the data of those items. + * + * The storage for the fsw_shandle structure is provided by the caller. Th= e dnode and pos + * fields may be accessed, pos may also be written to to set the file poin= ter. The file's + * data size is available as shand->dnode->size. + * + * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_= close to release + * the dnode reference held by the shandle. + */ + +fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *s= hand) +{ + fsw_status_t status; + struct fsw_volume *vol =3D dno->vol; + =20 + // read full dnode information into memory + status =3D vol->fstype_table->dnode_fill(vol, dno); + if (status) + return status; + =20 + // setup shandle + fsw_dnode_retain(dno); + =20 + shand->dnode =3D dno; + shand->pos =3D 0; + shand->extent.type =3D FSW_EXTENT_TYPE_INVALID; + =20 + return FSW_SUCCESS; +} + +/** + * Close a shandle after accessing the dnode's data. This function is call= ed by the host + * driver or core functions when they are finished with accessing a file's= data. It + * releases the dnode reference and frees any buffers associated with the = shandle itself. + * The dnode is only released if this was the last reference using it. + */ + +void fsw_shandle_close(struct fsw_shandle *shand) +{ + if (shand->extent.type =3D=3D FSW_EXTENT_TYPE_BUFFER) + fsw_free(shand->extent.buffer); + fsw_dnode_release(shand->dnode); +} + +/** + * Read data from a shandle (storage handle for a dnode). This function is= called by the + * host driver or internally when data is read from a file. TODO: more + */ + +fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_s= ize_inout, void *buffer_in) +{ + fsw_status_t status; + struct fsw_dnode *dno =3D shand->dnode; + struct fsw_volume *vol =3D dno->vol; + fsw_u8 *buffer, *block_buffer; + fsw_u32 buflen, copylen, pos; + fsw_u32 log_bno, pos_in_extent, phys_bno, pos_in_physblock; + fsw_u32 cache_level; + =20 + if (shand->pos >=3D dno->size) { // already at EOF + *buffer_size_inout =3D 0; + return FSW_SUCCESS; + } + =20 + // initialize vars + buffer =3D buffer_in; + buflen =3D *buffer_size_inout; + pos =3D (fsw_u32)shand->pos; + cache_level =3D (dno->type !=3D FSW_DNODE_TYPE_FILE) ? 1 : 0; + // restrict read to file size + if (buflen > dno->size - pos) + buflen =3D (fsw_u32)(dno->size - pos); + =20 + while (buflen > 0) { + // get extent for the current logical block + log_bno =3D pos / vol->log_blocksize; + if (shand->extent.type =3D=3D FSW_EXTENT_TYPE_INVALID || + log_bno < shand->extent.log_start || + log_bno >=3D shand->extent.log_start + shand->extent.log_count= ) { + =20 + if (shand->extent.type =3D=3D FSW_EXTENT_TYPE_BUFFER) + fsw_free(shand->extent.buffer); + =20 + // ask the file system for the proper extent + shand->extent.log_start =3D log_bno; + status =3D vol->fstype_table->get_extent(vol, dno, &shand->ext= ent); + if (status) { + shand->extent.type =3D FSW_EXTENT_TYPE_INVALID; + return status; + } + } + =20 + pos_in_extent =3D pos - shand->extent.log_start * vol->log_blocksi= ze; + =20 + // dispatch by extent type + if (shand->extent.type =3D=3D FSW_EXTENT_TYPE_PHYSBLOCK) { + // convert to physical block number and offset + phys_bno =3D shand->extent.phys_start + pos_in_extent / vol->p= hys_blocksize; + pos_in_physblock =3D pos_in_extent & (vol->phys_blocksize - 1); + copylen =3D vol->phys_blocksize - pos_in_physblock; + if (copylen > buflen) + copylen =3D buflen; + =20 + // get one physical block + status =3D fsw_block_get(vol, phys_bno, cache_level, (void **)= &block_buffer); + if (status) + return status; + =20 + // copy data from it + fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen); + fsw_block_release(vol, phys_bno, block_buffer); + =20 + } else if (shand->extent.type =3D=3D FSW_EXTENT_TYPE_BUFFER) { + copylen =3D shand->extent.log_count * vol->log_blocksize - pos= _in_extent; + if (copylen > buflen) + copylen =3D buflen; + fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_ext= ent, copylen); + =20 + } else { // _SPARSE or _INVALID + copylen =3D shand->extent.log_count * vol->log_blocksize - pos= _in_extent; + if (copylen > buflen) + copylen =3D buflen; + fsw_memzero(buffer, copylen); + =20 + } + =20 + buffer +=3D copylen; + buflen -=3D copylen; + pos +=3D copylen; + } + =20 + *buffer_size_inout =3D (fsw_u32)(pos - shand->pos); + shand->pos =3D pos; + =20 + return FSW_SUCCESS; +} + +// EOF diff --git a/OvmfPkg/FswHfsPlus/fsw_core.h b/OvmfPkg/FswHfsPlus/fsw_core.h new file mode 100644 index 0000000..0041ce1 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_core.h @@ -0,0 +1,517 @@ +/** + * \file fsw_core.h + * Core file system wrapper abstraction layer header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * Portions Copyright (c) The Regents of the University of California. + * Portions Copyright (c) UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#ifndef _FSW_CORE_H_ +#define _FSW_CORE_H_ + +#include "fsw_base.h" + + +/** Maximum size for a path, specifically symlink target paths. */ +#define FSW_PATH_MAX (4096) + +/** Helper macro for token concatenation. */ +#define FSW_CONCAT3(a,b,c) a##b##c +/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for = a named file system type. */ +#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table) + +/** Indicates that the block cache entry is empty. */ +#define FSW_INVALID_BNO (~0UL) + + +// +// Byte-swapping macros +// + + +/** + * \name Byte Order Macros + * Implements big endian vs. little endian awareness and conversion. + */ +/*@{*/ + +typedef fsw_u16 fsw_u16_le; +typedef fsw_u16 fsw_u16_be; +typedef fsw_u32 fsw_u32_le; +typedef fsw_u32 fsw_u32_be; +typedef fsw_u64 fsw_u64_le; +typedef fsw_u64 fsw_u64_be; + +#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \ + (((fsw_u16)(v) & 0x00ff) << 8)) +#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \ + (((fsw_u32)(v) & 0x00ff0000UL) >> 8) | \ + (((fsw_u32)(v) & 0x0000ff00UL) << 8) | \ + (((fsw_u32)(v) & 0x000000ffUL) << 24)) +#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 5= 6) | \ + (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 4= 0) | \ + (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 2= 4) | \ + (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8= ) | \ + (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8= ) | \ + (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 2= 4) | \ + (((fsw_u64)(v) & 0x000000000000ff00ULL) << 4= 0) | \ + (((fsw_u64)(v) & 0x00000000000000ffULL) << 5= 6)) + +#ifdef FSW_LITTLE_ENDIAN + +#define fsw_u16_le_swap(v) (v) +#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v) +#define fsw_u32_le_swap(v) (v) +#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v) +#define fsw_u64_le_swap(v) (v) +#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v) + +#define fsw_u16_le_sip(var) +#define fsw_u16_be_sip(var) (var =3D FSW_SWAPVALUE_U16(var)) +#define fsw_u32_le_sip(var) +#define fsw_u32_be_sip(var) (var =3D FSW_SWAPVALUE_U32(var)) +#define fsw_u64_le_sip(var) +#define fsw_u64_be_sip(var) (var =3D FSW_SWAPVALUE_U64(var)) + +#else +#ifdef FSW_BIG_ENDIAN + +#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v) +#define fsw_u16_be_swap(v) (v) +#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v) +#define fsw_u32_be_swap(v) (v) +#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v) +#define fsw_u64_be_swap(v) (v) + +#define fsw_u16_le_sip(var) (var =3D FSW_SWAPVALUE_U16(var)) +#define fsw_u16_be_sip(var) +#define fsw_u32_le_sip(var) (var =3D FSW_SWAPVALUE_U32(var)) +#define fsw_u32_be_sip(var) +#define fsw_u64_le_sip(var) (var =3D FSW_SWAPVALUE_U64(var)) +#define fsw_u64_be_sip(var) + +#else +#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined +#endif +#endif + +/*@}*/ + + +// +// The following evil hack avoids a lot of casts between generic and fstyp= e-specific +// structures. +// + +#ifndef VOLSTRUCTNAME +#define VOLSTRUCTNAME fsw_volume +#else +struct VOLSTRUCTNAME; +#endif +#ifndef DNODESTRUCTNAME +#define DNODESTRUCTNAME fsw_dnode +#else +struct DNODESTRUCTNAME; +#endif + + +/** + * Status code type, returned from all functions that can fail. + */ +typedef int fsw_status_t; + +/** + * Possible status codes. + */ +enum { + FSW_SUCCESS, + FSW_OUT_OF_MEMORY, + FSW_IO_ERROR, + FSW_UNSUPPORTED, + FSW_NOT_FOUND, + FSW_VOLUME_CORRUPTED, + FSW_UNKNOWN_ERROR +}; + + +/** + * Core: A string with explicit length and encoding information. + */ + +struct fsw_string { + int type; //!< Encoding of the string - empty, I= SO-8859-1, UTF8, UTF16 + int len; //!< Length in characters + int size; //!< Total data size in bytes + void *data; //!< Data pointer (may be NULL if type= is EMPTY or len is zero) +}; + +/** + * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY, + * all other members of the fsw_string structure may be invalid. + */ +enum { + FSW_STRING_TYPE_EMPTY, + FSW_STRING_TYPE_ISO88591, + FSW_STRING_TYPE_UTF8, + FSW_STRING_TYPE_UTF16, + FSW_STRING_TYPE_UTF16_SWAPPED +}; + +#ifdef FSW_LITTLE_ENDIAN +#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16 +#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED +#else +#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED +#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16 +#endif + +/** Static initializer for an empty string. */ +#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL } + + +/* forward declarations */ + +struct fsw_dnode; +struct fsw_host_table; +struct fsw_fstype_table; + +struct fsw_blockcache { + fsw_u32 refcount; //!< Reference count + fsw_u32 cache_level; //!< Level of importance of this block + fsw_u32 phys_bno; //!< Physical block number + void *data; //!< Block data buffer +}; + +/** + * Core: Represents a mounted volume. + */ + +struct fsw_volume { + fsw_u32 phys_blocksize; //!< Block size for disk access / file= system structures + fsw_u32 log_blocksize; //!< Block size for logical file data + =20 + struct DNODESTRUCTNAME *root; //!< Root directory dnode + struct fsw_string label; //!< Volume label + =20 + struct fsw_dnode *dnode_head; //!< List of all dnodes allocated for = this volume + =20 + struct fsw_blockcache *bcache; //!< Array of block cache entries + fsw_u32 bcache_size; //!< Number of entries in the block ca= che array + =20 + void *host_data; //!< Hook for a host-specific data str= ucture + struct fsw_host_table *host_table; //!< Dispatch table for host-s= pecific functions + struct fsw_fstype_table *fstype_table; //!< Dispatch table for file s= ystem specific functions + int host_string_type; //!< String type used by the host envi= ronment +}; + +/** + * Core: Represents a "directory node" - a file, directory, symlink, whate= ver. + */ + +struct fsw_dnode { + fsw_u32 refcount; //!< Reference count + =20 + struct VOLSTRUCTNAME *vol; //!< The volume this dnode belongs to + struct DNODESTRUCTNAME *parent; //!< Parent directory dnode + struct fsw_string name; //!< Name of this item in the parent d= irectory + =20 + fsw_u32 dnode_id; //!< Unique id number (usually the ino= de number) + int type; //!< Type of the dnode - file, dir, sy= mlink, special + fsw_u64 size; //!< Data size in bytes + =20 + struct fsw_dnode *next; //!< Doubly-linked list of all dnodes:= previous dnode + struct fsw_dnode *prev; //!< Doubly-linked list of all dnodes:= next dnode +}; + +/** + * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before + * fsw_dnode_fill has been called on the dnode. + */ +enum { + FSW_DNODE_TYPE_UNKNOWN, + FSW_DNODE_TYPE_FILE, + FSW_DNODE_TYPE_DIR, + FSW_DNODE_TYPE_SYMLINK, + FSW_DNODE_TYPE_SPECIAL +}; + +/** + * Core: Stores the mapping of a region of a file to the data on disk. + */ + +struct fsw_extent { + int type; //!< Type of extent specification + fsw_u32 log_start; //!< Starting logical block number + fsw_u32 log_count; //!< Logical block count + fsw_u32 phys_start; //!< Starting physical block number (f= or FSW_EXTENT_TYPE_PHYSBLOCK only) + void *buffer; //!< Allocated buffer pointer (for FSW= _EXTENT_TYPE_BUFFER only) +}; + +/** + * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for sh= andle's + * internal use only, it must not be returned from a get_extent function. + */ +enum { + FSW_EXTENT_TYPE_INVALID, + FSW_EXTENT_TYPE_SPARSE, + FSW_EXTENT_TYPE_PHYSBLOCK, + FSW_EXTENT_TYPE_BUFFER +}; + +/** + * Core: An access structure to a dnode's raw data. There can be multiple + * shandles per dnode, each of them has its own position pointer. + */ + +struct fsw_shandle { + struct fsw_dnode *dnode; //!< The dnode this handle reads data = from + =20 + fsw_u64 pos; //!< Current file pointer in bytes + struct fsw_extent extent; //!< Current extent +}; + +/** + * Core: Used in gathering detailed information on a volume. + */ + +struct fsw_volume_stat { + fsw_u64 total_bytes; //!< Total size of data area size in b= ytes + fsw_u64 free_bytes; //!< Bytes still available for storing= file data +}; + +/** + * Core: Used in gathering detailed information on a dnode. + */ + +struct fsw_dnode_stat { + fsw_u64 used_bytes; //!< Bytes actually used by the file o= n disk + void (*store_time_posix)(struct fsw_dnode_stat *sb, int which, = fsw_u32 posix_time); //!< Callback for storing a Posix-style timestamp + void (*store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 pos= ix_mode); //!< Callbock for storing a Posix-style file mode + void *host_data; //!< Hook for a host-specific data str= ucture +}; + +/** + * Type of the timestamp passed into store_time_posix. + */ +enum { + FSW_DNODE_STAT_CTIME, + FSW_DNODE_STAT_MTIME, + FSW_DNODE_STAT_ATIME +}; + +/** + * Core: Function table for a host environment. + */ + +struct fsw_host_table +{ + int native_string_type; //!< String type used by the host envi= ronment + =20 + void (*change_blocksize)(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 o= ld_log_blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 n= ew_log_blocksize); + fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u32 phys_bno, v= oid *buffer); +}; + +/** + * Core: Function table for a file system driver. + */ + +struct fsw_fstype_table +{ + struct fsw_string name; //!< String giving the name of the fil= e system + fsw_u32 volume_struct_size; //!< Size for allocating the fsw_volum= e structure + fsw_u32 dnode_struct_size; //!< Size for allocating the fsw_dnode= structure + =20 + fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol); + void (*volume_free)(struct VOLSTRUCTNAME *vol); + fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volu= me_stat *sb); + =20 + fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRU= CTNAME *dno); + void (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRU= CTNAME *dno); + fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRU= CTNAME *dno, + struct fsw_dnode_stat *sb); + fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRU= CTNAME *dno, + struct fsw_extent *extent); + =20 + fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRU= CTNAME *dno, + struct fsw_string *lookup_name, struct DNOD= ESTRUCTNAME **child_dno); + fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCT= NAME *dno, + struct fsw_shandle *shand, struct DNODESTRUCT= NAME **child_dno); + fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCT= NAME *dno, + struct fsw_string *link_target); +}; + + +/** + * \name Volume Functions + */ +/*@{*/ + +fsw_status_t fsw_mount(void *host_data, + struct fsw_host_table *host_table, + struct fsw_fstype_table *fstype_table, + struct fsw_volume **vol_out); +void fsw_unmount(struct fsw_volume *vol); +fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_sta= t *sb); + +void fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blo= cksize, fsw_u32 log_blocksize); +fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fs= w_u32 cache_level, void **buffer_out); +void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno= , void *buffer); + +/*@}*/ + + +/** + * \name dnode Functions + */ +/*@{*/ + +fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u32 dnod= e_id, struct DNODESTRUCTNAME **dno_out); +fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u32 = dnode_id, int type, + struct fsw_string *name, struct DNODESTRUCTN= AME **dno_out); +void fsw_dnode_retain(struct fsw_dnode *dno); +void fsw_dnode_release(struct fsw_dnode *dno); + +fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno); +fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *= sb); + +fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno, + struct fsw_string *lookup_name, struct fsw_d= node **child_dno_out); +fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno, + struct fsw_string *lookup_path, char se= parator, + struct fsw_dnode **child_dno_out); +fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnod= e **child_dno_out); +fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *= link_target); +fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct f= sw_string *link_target); +fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **t= arget_dno_out); + +/*@}*/ + + +/** + * \name shandle Functions + */ +/*@{*/ + +fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shan= dle *shand); +void fsw_shandle_close(struct fsw_shandle *shand); +fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_s= ize_inout, void *buffer); + +/*@}*/ + + +/** + * \name Memory Functions + */ +/*@{*/ + +fsw_status_t fsw_alloc_zero(int len, void **ptr_out); +fsw_status_t fsw_memdup(void **dest_out, void *src, int len); + +/*@}*/ + + +/** + * \name String Functions + */ +/*@{*/ + +int fsw_strlen(struct fsw_string *s); +int fsw_streq(struct fsw_string *s1, struct fsw_string *s2); +int fsw_streq_cstr(struct fsw_string *s1, const char *s2); +fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct f= sw_string *src); +void fsw_strsplit(struct fsw_string *lookup_name, struct fsw_strin= g *buffer, char separator); + +void fsw_strfree(struct fsw_string *s); + +/*@}*/ + + +/** + * \name Posix Mode Macros + * These macros can be used globally to test fields and bits in + * Posix-style modes. + * + * Taken from FreeBSD sys/stat.h. + */ +/*@{*/ +#ifndef S_IRWXU + +#define S_ISUID 0004000 /* set user id on execution */ +#define S_ISGID 0002000 /* set group id on execution */ +#define S_ISTXT 0001000 /* sticky bit */ + +#define S_IRWXU 0000700 /* RWX mask for owner */ +#define S_IRUSR 0000400 /* R for owner */ +#define S_IWUSR 0000200 /* W for owner */ +#define S_IXUSR 0000100 /* X for owner */ + +#define S_IRWXG 0000070 /* RWX mask for group */ +#define S_IRGRP 0000040 /* R for group */ +#define S_IWGRP 0000020 /* W for group */ +#define S_IXGRP 0000010 /* X for group */ + +#define S_IRWXO 0000007 /* RWX mask for other */ +#define S_IROTH 0000004 /* R for other */ +#define S_IWOTH 0000002 /* W for other */ +#define S_IXOTH 0000001 /* X for other */ + +#define S_IFMT 0170000 /* type of file mask */ +#define S_IFIFO 0010000 /* named pipe (fifo) */ +#define S_IFCHR 0020000 /* character special */ +#define S_IFDIR 0040000 /* directory */ +#define S_IFBLK 0060000 /* block special */ +#define S_IFREG 0100000 /* regular */ +#define S_IFLNK 0120000 /* symbolic link */ +#define S_IFSOCK 0140000 /* socket */ +#define S_ISVTX 0001000 /* save swapped text even after use */ +#define S_IFWHT 0160000 /* whiteout */ + +#define S_ISDIR(m) (((m) & 0170000) =3D=3D 0040000) /* directory */ +#define S_ISCHR(m) (((m) & 0170000) =3D=3D 0020000) /* char special */ +#define S_ISBLK(m) (((m) & 0170000) =3D=3D 0060000) /* block special */ +#define S_ISREG(m) (((m) & 0170000) =3D=3D 0100000) /* regular file */ +#define S_ISFIFO(m) (((m) & 0170000) =3D=3D 0010000) /* fifo or socket */ +#define S_ISLNK(m) (((m) & 0170000) =3D=3D 0120000) /* symbolic link */ +#define S_ISSOCK(m) (((m) & 0170000) =3D=3D 0140000) /* socket */ +#define S_ISWHT(m) (((m) & 0170000) =3D=3D 0160000) /* whiteout */ + +#define S_BLKSIZE 512 /* block size used in the stat struct */ + +#endif +/*@}*/ + + +#endif diff --git a/OvmfPkg/FswHfsPlus/fsw_efi.c b/OvmfPkg/FswHfsPlus/fsw_efi.c new file mode 100644 index 0000000..c024162 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_efi.c @@ -0,0 +1,1044 @@ +/** + * \file fsw_efi.c + * EFI host environment code. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#include "fsw_efi.h" + +#define DEBUG_LEVEL 0 + + +#ifndef FSTYPE +/** The file system type name to use. */ +#define FSTYPE ext2 +#endif + +/** Helper macro for stringification. */ +#define FSW_EFI_STRINGIFY(x) L#x +/** Expands to the EFI driver name given the file system type name. */ +#define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System= Driver" + +// function prototypes + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PR= OTOCOL *This, + IN EFI_HANDLE = ControllerHandle, + IN EFI_DEVICE_PATH_PROTO= COL *RemainingDevicePath); +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOC= OL *This, + IN EFI_HANDLE = ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL = *RemainingDevicePath); +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOC= OL *This, + IN EFI_HANDLE = ControllerHandle, + IN UINTN = NumberOfChildren, + IN EFI_HANDLE = *ChildHandleBuffer); + +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NA= ME_PROTOCOL *This, + IN CHAR8 = *Language, + OUT CHAR16 = **DriverName); +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONEN= T_NAME_PROTOCOL *This, + IN EFI_HANDLE = ControllerHandle, + IN EFI_HANDLE = ChildHandle OPTIONAL, + IN CHAR8 = *Language, + OUT CHAR16 = **ControllerName); + +void fsw_efi_change_blocksize(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_= blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_= blocksize); +fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, = void *buffer); + +EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Vo= lume); + +EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *= This, + OUT EFI_FILE **Root); +EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, + OUT EFI_FILE **NewFileHandle); + +EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); +EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, + OUT UINT64 *Position); +EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, + IN UINT64 Position); + +EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes); +EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); +EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, + IN UINT64 Position); + +EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); +EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, + IN struct fsw_dnode *dno, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer); + +/** + * Interface structure for the EFI Driver Binding protocol. + */ + +EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table =3D { + fsw_efi_DriverBinding_Supported, + fsw_efi_DriverBinding_Start, + fsw_efi_DriverBinding_Stop, + 0x10, + NULL, + NULL +}; + +/** + * Interface structure for the EFI Component Name protocol. + */ + +EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table =3D { + fsw_efi_ComponentName_GetDriverName, + fsw_efi_ComponentName_GetControllerName, + "eng" +}; + +/** + * Dispatch table for our FSW host driver. + */ + +struct fsw_host_table fsw_efi_host_table =3D { + FSW_STRING_TYPE_UTF16, + =20 + fsw_efi_change_blocksize, + fsw_efi_read_block +}; + +extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); + + +EFI_DRIVER_ENTRY_POINT(fsw_efi_main) + +/** + * Image entry point. Installs the Driver Binding and Component Name proto= cols + * on the image's handle. Actually mounting a file system is initiated thr= ough + * the Driver Binding protocol at the firmware's request. + */ + +EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + =20 + InitializeLib(ImageHandle, SystemTable); + =20 + // complete Driver Binding protocol instance + fsw_efi_DriverBinding_table.ImageHandle =3D ImageHandle; + fsw_efi_DriverBinding_table.DriverBindingHandle =3D ImageHandle; + // install Driver Binding protocol + Status =3D BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.D= riverBindingHandle, + &DriverBindingProtocol, + EFI_NATIVE_INTERFACE, + &fsw_efi_DriverBinding_table); + if (EFI_ERROR (Status)) { + return Status; + } + =20 + // install Component Name protocol + Status =3D BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.D= riverBindingHandle, + &ComponentNameProtocol, + EFI_NATIVE_INTERFACE, + &fsw_efi_ComponentName_table); + if (EFI_ERROR (Status)) { + return Status; + } + =20 + return EFI_SUCCESS; +} + +/** + * Driver Binding EFI protocol, Supported function. This function is calle= d by EFI + * to test if this driver can handle a certain device. Our implementation = only checks + * if the device is a disk (i.e. that it supports the Block I/O and Disk I= /O protocols) + * and implicitly checks if the disk is already in use by another driver. + */ + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PR= OTOCOL *This, + IN EFI_HANDLE = ControllerHandle, + IN EFI_DEVICE_PATH_PROTO= COL *RemainingDevicePath) +{ + EFI_STATUS Status; + EFI_DISK_IO *DiskIo; + =20 + // we check for both DiskIO and BlockIO protocols + =20 + // first, open DiskIO + Status =3D BS->OpenProtocol(ControllerHandle, + &DiskIoProtocol, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR(Status)) + return Status; + =20 + // we were just checking, close it again + BS->CloseProtocol(ControllerHandle, + &DiskIoProtocol, + This->DriverBindingHandle, + ControllerHandle); + =20 + // next, check BlockIO without actually opening it + Status =3D BS->OpenProtocol(ControllerHandle, + &BlockIoProtocol, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + return Status; +} + +/** + * Driver Binding EFI protocol, Start function. This function is called by= EFI + * to start driving the given device. It is still possible at this point to + * return EFI_UNSUPPORTED, and in fact we will do so if the file system dr= iver + * cannot find the superblock signature (or equivalent) that it expects. + * + * This function allocates memory for a per-volume structure, opens the + * required protocols (just Disk I/O in our case, Block I/O is only looked + * at to get the MediaId field), and lets the FSW core mount the file syst= em. + * If successful, an EFI Simple File System protocol is exported on the + * device handle. + */ + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOC= OL *This, + IN EFI_HANDLE = ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL = *RemainingDevicePath) +{ + EFI_STATUS Status; + EFI_BLOCK_IO *BlockIo; + EFI_DISK_IO *DiskIo; + FSW_VOLUME_DATA *Volume; + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_DriverBinding_Start\n"); +#endif + =20 + // open consumed protocols + Status =3D BS->OpenProtocol(ControllerHandle, + &BlockIoProtocol, + (VOID **) &BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: = we only want to look at the MediaId + if (EFI_ERROR(Status)) { + Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status); + return Status; + } + =20 + Status =3D BS->OpenProtocol(ControllerHandle, + &DiskIoProtocol, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR(Status)) { + Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status); + return Status; + } + =20 + // allocate volume structure + Volume =3D AllocateZeroPool(sizeof(FSW_VOLUME_DATA)); + Volume->Signature =3D FSW_VOLUME_DATA_SIGNATURE; + Volume->Handle =3D ControllerHandle; + Volume->DiskIo =3D DiskIo; + Volume->MediaId =3D BlockIo->Media->MediaId; + Volume->LastIOStatus =3D EFI_SUCCESS; + =20 + // mount the filesystem + Status =3D fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table, + &FSW_FSTYPE_TABLE_NAME(FSTYPE), = &Volume->vol), + Volume); + =20 + if (!EFI_ERROR(Status)) { + // register the SimpleFileSystem protocol + Volume->FileSystem.Revision =3D EFI_FILE_IO_INTERFACE_REVISION; + Volume->FileSystem.OpenVolume =3D fsw_efi_FileSystem_OpenVolume; + Status =3D BS->InstallMultipleProtocolInterfaces(&ControllerHandle, + &FileSystemProtocol= , &Volume->FileSystem, + NULL); + if (EFI_ERROR(Status)) + Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned = %x\n", Status); + } + =20 + // on errors, close the opened protocols + if (EFI_ERROR(Status)) { + if (Volume->vol !=3D NULL) + fsw_unmount(Volume->vol); + FreePool(Volume); + =20 + BS->CloseProtocol(ControllerHandle, + &DiskIoProtocol, + This->DriverBindingHandle, + ControllerHandle); + } + =20 + return Status; +} + +/** + * Driver Binding EFI protocol, Stop function. This function is called by = EFI + * to stop the driver on the given device. This translates to an unmount + * call for the FSW core. + * + * We assume that all file handles on the volume have been closed before + * the driver is stopped. At least with the EFI shell, that is actually the + * case; it closes all file handles between commands. + */ + +EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOC= OL *This, + IN EFI_HANDLE = ControllerHandle, + IN UINTN = NumberOfChildren, + IN EFI_HANDLE = *ChildHandleBuffer) +{ + EFI_STATUS Status; + EFI_FILE_IO_INTERFACE *FileSystem; + FSW_VOLUME_DATA *Volume; + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_DriverBinding_Stop\n"); +#endif + =20 + // get the installed SimpleFileSystem interface + Status =3D BS->OpenProtocol(ControllerHandle, + &FileSystemProtocol, + (VOID **) &FileSystem, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) + return EFI_UNSUPPORTED; + =20 + // get private data structure + Volume =3D FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem); + =20 + // uninstall Simple File System protocol + Status =3D BS->UninstallMultipleProtocolInterfaces(ControllerHandle, + &FileSystemProtocol, = &Volume->FileSystem, + NULL); + if (EFI_ERROR(Status)) { + Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x= \n", Status); + return Status; + } +#if DEBUG_LEVEL + Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\= n"); +#endif + =20 + // release private data structure + if (Volume->vol !=3D NULL) + fsw_unmount(Volume->vol); + FreePool(Volume); + =20 + // close the consumed protocols + Status =3D BS->CloseProtocol(ControllerHandle, + &DiskIoProtocol, + This->DriverBindingHandle, + ControllerHandle); + =20 + return Status; +} + +/** + * Component Name EFI protocol, GetDriverName function. Used by the EFI + * environment to inquire the name of this driver. The name returned is + * based on the file system type actually used in compilation. + */ + +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NA= ME_PROTOCOL *This, + IN CHAR8 = *Language, + OUT CHAR16 = **DriverName) +{ + if (Language =3D=3D NULL || DriverName =3D=3D NULL) + return EFI_INVALID_PARAMETER; + =20 + if (Language[0] =3D=3D 'e' && Language[1] =3D=3D 'n' && Language[2] = =3D=3D 'g' && Language[3] =3D=3D 0) { + *DriverName =3D FSW_EFI_DRIVER_NAME(FSTYPE); + return EFI_SUCCESS; + } + return EFI_UNSUPPORTED; +} + +/** + * Component Name EFI protocol, GetControllerName function. Not implemented + * because this is not a "bus" driver in the sense of the EFI Driver Model. + */ + +EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONEN= T_NAME_PROTOCOL *This, + IN EFI_HANDLE = ControllerHandle, + IN EFI_HANDLE = ChildHandle OPTIONAL, + IN CHAR8 = *Language, + OUT CHAR16 = **ControllerName) +{ + return EFI_UNSUPPORTED; +} + +/** + * FSW interface function for block size changes. This function is called = by the FSW core + * when the file system driver changes the block sizes for the volume. + */ + +void fsw_efi_change_blocksize(struct fsw_volume *vol, + fsw_u32 old_phys_blocksize, fsw_u32 old_log_= blocksize, + fsw_u32 new_phys_blocksize, fsw_u32 new_log_= blocksize) +{ + // nothing to do +} + +/** + * FSW interface function to read data blocks. This function is called by = the FSW core + * to read a block of data from the device. The buffer is allocated by the= core code. + */ + +fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, = void *buffer) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume =3D (FSW_VOLUME_DATA *)vol->host_data; + =20 + FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno= , vol->phys_blocksize)); + =20 + // read from disk + Status =3D Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId, + (UINT64)phys_bno * vol->phys_blocksi= ze, + vol->phys_blocksize, + buffer); + Volume->LastIOStatus =3D Status; + if (EFI_ERROR(Status)) + return FSW_IO_ERROR; + return FSW_SUCCESS; +} + +/** + * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only= produced + * by fsw_efi_read_block, so we map it back to the EFI status code remembe= red from + * the last I/O operation. + */ + +EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Vo= lume) +{ + switch (fsw_status) { + case FSW_SUCCESS: + return EFI_SUCCESS; + case FSW_OUT_OF_MEMORY: + return EFI_VOLUME_CORRUPTED; + case FSW_IO_ERROR: + return Volume->LastIOStatus; + case FSW_UNSUPPORTED: + return EFI_UNSUPPORTED; + case FSW_NOT_FOUND: + return EFI_NOT_FOUND; + case FSW_VOLUME_CORRUPTED: + return EFI_VOLUME_CORRUPTED; + default: + return EFI_DEVICE_ERROR; + } +} + +/** + * File System EFI protocol, OpenVolume function. Creates a file handle for + * the root directory and returns it. Note that this function may be called + * multiple times and returns a new file handle each time. Each returned + * handle is closed by the client using it. + */ + +EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *= This, + OUT EFI_FILE **Root) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume =3D FSW_VOLUME_FROM_FILE_SYSTEM(This); + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_FileSystem_OpenVolume\n"); +#endif + =20 + Status =3D fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root); + =20 + return Status; +} + +/** + * File Handle EFI protocol, Open function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes) +{ + FSW_FILE_DATA *File =3D FSW_FILE_FROM_FILE_HANDLE(This); + =20 + if (File->Type =3D=3D FSW_EFI_FILE_TYPE_DIR) + return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attri= butes); + // not supported for regular files + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, Close function. Closes the FSW shandle + * and frees the memory used for the structure. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This) +{ + FSW_FILE_DATA *File =3D FSW_FILE_FROM_FILE_HANDLE(This); + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_FileHandle_Close\n"); +#endif + =20 + fsw_shandle_close(&File->shand); + FreePool(File); + =20 + return EFI_SUCCESS; +} + +/** + * File Handle EFI protocol, Delete function. Calls through to Close + * and returns a warning because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This) +{ + EFI_STATUS Status; + =20 + Status =3D This->Close(This); + if (Status =3D=3D EFI_SUCCESS) { + // this driver is read-only + Status =3D EFI_WARN_DELETE_FAILURE; + } + =20 + return Status; +} + +/** + * File Handle EFI protocol, Read function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + FSW_FILE_DATA *File =3D FSW_FILE_FROM_FILE_HANDLE(This); + =20 + if (File->Type =3D=3D FSW_EFI_FILE_TYPE_FILE) + return fsw_efi_file_read(File, BufferSize, Buffer); + else if (File->Type =3D=3D FSW_EFI_FILE_TYPE_DIR) + return fsw_efi_dir_read(File, BufferSize, Buffer); + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, Write function. Returns unsupported status + * because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer) +{ + // this driver is read-only + return EFI_WRITE_PROTECTED; +} + +/** + * File Handle EFI protocol, GetPosition function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This, + OUT UINT64 *Position) +{ + FSW_FILE_DATA *File =3D FSW_FILE_FROM_FILE_HANDLE(This); + =20 + if (File->Type =3D=3D FSW_EFI_FILE_TYPE_FILE) + return fsw_efi_file_getpos(File, Position); + // not defined for directories + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, SetPosition function. Dispatches the call + * based on the kind of file handle. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This, + IN UINT64 Position) +{ + FSW_FILE_DATA *File =3D FSW_FILE_FROM_FILE_HANDLE(This); + =20 + if (File->Type =3D=3D FSW_EFI_FILE_TYPE_FILE) + return fsw_efi_file_setpos(File, Position); + else if (File->Type =3D=3D FSW_EFI_FILE_TYPE_DIR) + return fsw_efi_dir_setpos(File, Position); + return EFI_UNSUPPORTED; +} + +/** + * File Handle EFI protocol, GetInfo function. Dispatches to the common + * function implementing this. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + FSW_FILE_DATA *File =3D FSW_FILE_FROM_FILE_HANDLE(This); + =20 + return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer= ); +} + +/** + * File Handle EFI protocol, SetInfo function. Returns unsupported status + * because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer) +{ + // this driver is read-only + return EFI_WRITE_PROTECTED; +} + +/** + * File Handle EFI protocol, Flush function. Returns unsupported status + * because this driver is read-only. + */ + +EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This) +{ + // this driver is read-only + return EFI_WRITE_PROTECTED; +} + +/** + * Set up a file handle for a dnode. This function allocates a data struct= ure + * for a file handle, opens a FSW shandle and populates the EFI_FILE struc= ture + * with the interface functions. + */ + +EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno, + OUT EFI_FILE **NewFileHandle) +{ + EFI_STATUS Status; + FSW_FILE_DATA *File; + =20 + // make sure the dnode has complete info + Status =3D fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)= dno->vol->host_data); + if (EFI_ERROR(Status)) + return Status; + =20 + // check type + if (dno->type !=3D FSW_DNODE_TYPE_FILE && dno->type !=3D FSW_DNODE_TYP= E_DIR) + return EFI_UNSUPPORTED; + =20 + // allocate file structure + File =3D AllocateZeroPool(sizeof(FSW_FILE_DATA)); + File->Signature =3D FSW_FILE_DATA_SIGNATURE; + if (dno->type =3D=3D FSW_DNODE_TYPE_FILE) + File->Type =3D FSW_EFI_FILE_TYPE_FILE; + else if (dno->type =3D=3D FSW_DNODE_TYPE_DIR) + File->Type =3D FSW_EFI_FILE_TYPE_DIR; + =20 + // open shandle + Status =3D fsw_efi_map_status(fsw_shandle_open(dno, &File->shand), + (FSW_VOLUME_DATA *)dno->vol->host_data); + if (EFI_ERROR(Status)) { + FreePool(File); + return Status; + } + =20 + // populate the file handle + File->FileHandle.Revision =3D EFI_FILE_HANDLE_REVISION; + File->FileHandle.Open =3D fsw_efi_FileHandle_Open; + File->FileHandle.Close =3D fsw_efi_FileHandle_Close; + File->FileHandle.Delete =3D fsw_efi_FileHandle_Delete; + File->FileHandle.Read =3D fsw_efi_FileHandle_Read; + File->FileHandle.Write =3D fsw_efi_FileHandle_Write; + File->FileHandle.GetPosition =3D fsw_efi_FileHandle_GetPosition; + File->FileHandle.SetPosition =3D fsw_efi_FileHandle_SetPosition; + File->FileHandle.GetInfo =3D fsw_efi_FileHandle_GetInfo; + File->FileHandle.SetInfo =3D fsw_efi_FileHandle_SetInfo; + File->FileHandle.Flush =3D fsw_efi_FileHandle_Flush; + =20 + *NewFileHandle =3D &File->FileHandle; + return EFI_SUCCESS; +} + +/** + * Data read function for regular files. Calls through to fsw_shandle_read. + */ + +EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + fsw_u32 buffer_size; + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_file_read %d bytes\n", *BufferSize); +#endif + =20 + buffer_size =3D *BufferSize; + Status =3D fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_s= ize, Buffer), + (FSW_VOLUME_DATA *)File->shand.dnode->vol-= >host_data); + *BufferSize =3D buffer_size; + =20 + return Status; +} + +/** + * Get file position for regular files. + */ + +EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File, + OUT UINT64 *Position) +{ + *Position =3D File->shand.pos; + return EFI_SUCCESS; +} + +/** + * Set file position for regular files. EFI specifies the all-ones value + * to be a special value for the end of the file. + */ + +EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, + IN UINT64 Position) +{ + if (Position =3D=3D 0xFFFFFFFFFFFFFFFFULL) + File->shand.pos =3D File->shand.dnode->size; + else + File->shand.pos =3D Position; + return EFI_SUCCESS; +} + +/** + * Open function used to open new file handles relative to a directory. + * In EFI, the "open file" function is implemented by directory file handl= es + * and is passed a relative or volume-absolute path to the file or directo= ry + * to open. We use fsw_dnode_lookup_path to find the node plus an addition= al + * call to fsw_dnode_resolve because EFI has no concept of symbolic links. + */ + +EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File, + OUT EFI_FILE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume =3D (FSW_VOLUME_DATA *)File->shand.dnode->= vol->host_data; + struct fsw_dnode *dno; + struct fsw_dnode *target_dno; + struct fsw_string lookup_path; + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_dir_open: '%s'\n", FileName); +#endif + =20 + if (OpenMode !=3D EFI_FILE_MODE_READ) + return EFI_WRITE_PROTECTED; + =20 + lookup_path.type =3D FSW_STRING_TYPE_UTF16; + lookup_path.len =3D StrLen(FileName); + lookup_path.size =3D lookup_path.len * sizeof(fsw_u16); + lookup_path.data =3D FileName; + =20 + // resolve the path (symlinks along the way are automatically resolved) + Status =3D fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode,= &lookup_path, '\\', &dno), + Volume); + if (EFI_ERROR(Status)) + return Status; + =20 + // if the final node is a symlink, also resolve it + Status =3D fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), + Volume); + fsw_dnode_release(dno); + if (EFI_ERROR(Status)) + return Status; + dno =3D target_dno; + =20 + // make a new EFI handle for the target dnode + Status =3D fsw_efi_dnode_to_FileHandle(dno, NewHandle); + fsw_dnode_release(dno); + return Status; +} + +/** + * Read function for directories. A file handle read on a directory retrie= ves + * the next directory entry. + */ + +EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume =3D (FSW_VOLUME_DATA *)File->shand.dnode->= vol->host_data; + struct fsw_dnode *dno; + =20 +#if DEBUG_LEVEL + Print(L"fsw_efi_dir_read...\n"); +#endif + =20 + // read the next entry + Status =3D fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), + Volume); + if (Status =3D=3D EFI_NOT_FOUND) { + // end of directory + *BufferSize =3D 0; +#if DEBUG_LEVEL + Print(L"...no more entries\n"); +#endif + return EFI_SUCCESS; + } + if (EFI_ERROR(Status)) + return Status; + =20 + // get info into buffer + Status =3D fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer= ); + fsw_dnode_release(dno); + return Status; +} + +/** + * Set file position for directories. The only allowed set position operat= ion + * for directories is to rewind the directory completely by setting the + * position to zero. + */ + +EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, + IN UINT64 Position) +{ + if (Position =3D=3D 0) { + File->shand.pos =3D 0; + return EFI_SUCCESS; + } else { + // directories can only rewind to the start + return EFI_UNSUPPORTED; + } +} + +/** + * Get file or volume information. This function implements the GetInfo ca= ll + * for all file handles. Control is dispatched according to the type of in= formation + * requested by the caller. + */ + +EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + FSW_VOLUME_DATA *Volume =3D (FSW_VOLUME_DATA *)File->shand.dnode->= vol->host_data; + EFI_FILE_SYSTEM_INFO *FSInfo; + UINTN RequiredSize; + struct fsw_volume_stat vsb; + =20 + if (CompareGuid(InformationType, &GenericFileInfo) =3D=3D 0) { +#if DEBUG_LEVEL + Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n"); +#endif + =20 + Status =3D fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, = BufferSize, Buffer); + =20 + } else if (CompareGuid(InformationType, &FileSystemInfo) =3D=3D 0) { +#if DEBUG_LEVEL + Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n"); +#endif + =20 + // check buffer size + RequiredSize =3D SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&V= olume->vol->label); + if (*BufferSize < RequiredSize) { + *BufferSize =3D RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + =20 + // fill structure + FSInfo =3D (EFI_FILE_SYSTEM_INFO *)Buffer; + FSInfo->Size =3D RequiredSize; + FSInfo->ReadOnly =3D TRUE; + FSInfo->BlockSize =3D Volume->vol->log_blocksize; + fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label); + =20 + // get the missing info from the fs driver + ZeroMem(&vsb, sizeof(struct fsw_volume_stat)); + Status =3D fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), = Volume); + if (EFI_ERROR(Status)) + return Status; + FSInfo->VolumeSize =3D vsb.total_bytes; + FSInfo->FreeSpace =3D vsb.free_bytes; + =20 + // prepare for return + *BufferSize =3D RequiredSize; + Status =3D EFI_SUCCESS; + =20 + } else if (CompareGuid(InformationType, &FileSystemVolumeLabelInfo) = =3D=3D 0) { +#if DEBUG_LEVEL + Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n"); +#endif + =20 + // check buffer size + RequiredSize =3D SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_e= fi_strsize(&Volume->vol->label); + if (*BufferSize < RequiredSize) { + *BufferSize =3D RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + =20 + // copy volume label + fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->Volu= meLabel, &Volume->vol->label); + =20 + // prepare for return + *BufferSize =3D RequiredSize; + Status =3D EFI_SUCCESS; + =20 + } else { + Status =3D EFI_UNSUPPORTED; + } + =20 + return Status; +} + +/** + * Time mapping callback for the fsw_dnode_stat call. This function conver= ts + * a Posix style timestamp into an EFI_TIME structure and writes it to the + * appropriate member of the EFI_FILE_INFO structure that we're filling. + */ + +static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which,= fsw_u32 posix_time) +{ + EFI_FILE_INFO *FileInfo =3D (EFI_FILE_INFO *)sb->host_data; + =20 + if (which =3D=3D FSW_DNODE_STAT_CTIME) + fsw_efi_decode_time(&FileInfo->CreateTime, posix_time); + else if (which =3D=3D FSW_DNODE_STAT_MTIME) + fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time); + else if (which =3D=3D FSW_DNODE_STAT_ATIME) + fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time); +} + +/** + * Mode mapping callback for the fsw_dnode_stat call. This function looks = at + * the Posix mode passed by the file system driver and makes appropriate + * adjustments to the EFI_FILE_INFO structure that we're filling. + */ + +static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 po= six_mode) +{ + EFI_FILE_INFO *FileInfo =3D (EFI_FILE_INFO *)sb->host_data; + =20 + if ((posix_mode & S_IWUSR) =3D=3D 0) + FileInfo->Attribute |=3D EFI_FILE_READ_ONLY; +} + +/** + * Common function to fill an EFI_FILE_INFO with information about a dnode. + */ + +EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume, + IN struct fsw_dnode *dno, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + UINTN RequiredSize; + struct fsw_dnode_stat sb; + =20 + // make sure the dnode has complete info + Status =3D fsw_efi_map_status(fsw_dnode_fill(dno), Volume); + if (EFI_ERROR(Status)) + return Status; + =20 + // TODO: check/assert that the dno's name is in UTF16 + =20 + // check buffer size + RequiredSize =3D SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name); + if (*BufferSize < RequiredSize) { + // TODO: wind back the directory in this case + =20 +#if DEBUG_LEVEL + Print(L"...BUFFER TOO SMALL\n"); +#endif + *BufferSize =3D RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + =20 + // fill structure + ZeroMem(Buffer, RequiredSize); + FileInfo =3D (EFI_FILE_INFO *)Buffer; + FileInfo->Size =3D RequiredSize; + FileInfo->FileSize =3D dno->size; + FileInfo->Attribute =3D 0; + if (dno->type =3D=3D FSW_DNODE_TYPE_DIR) + FileInfo->Attribute |=3D EFI_FILE_DIRECTORY; + fsw_efi_strcpy(FileInfo->FileName, &dno->name); + =20 + // get the missing info from the fs driver + ZeroMem(&sb, sizeof(struct fsw_dnode_stat)); + sb.store_time_posix =3D fsw_efi_store_time_posix; + sb.store_attr_posix =3D fsw_efi_store_attr_posix; + sb.host_data =3D FileInfo; + Status =3D fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume); + if (EFI_ERROR(Status)) + return Status; + FileInfo->PhysicalSize =3D sb.used_bytes; + =20 + // prepare for return + *BufferSize =3D RequiredSize; +#if DEBUG_LEVEL + Print(L"...returning '%s'\n", FileInfo->FileName); +#endif + return EFI_SUCCESS; +} + +// EOF diff --git a/OvmfPkg/FswHfsPlus/fsw_efi.h b/OvmfPkg/FswHfsPlus/fsw_efi.h new file mode 100644 index 0000000..a6f58f3 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_efi.h @@ -0,0 +1,102 @@ +/** + * \file fsw_efi.h + * EFI host environment header. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#ifndef _FSW_EFI_H_ +#define _FSW_EFI_H_ + +#include "fsw_core.h" + + +/** + * EFI Host: Private per-volume structure. + */ + +typedef struct { + UINT64 Signature; //!< Used to identify this= structure + =20 + EFI_FILE_IO_INTERFACE FileSystem; //!< Published EFI protoco= l interface structure + =20 + EFI_HANDLE Handle; //!< The device handle the= protocol is attached to + EFI_DISK_IO *DiskIo; //!< The Disk I/O protocol= we use for disk access + UINT32 MediaId; //!< The media ID from the= Block I/O protocol + EFI_STATUS LastIOStatus; //!< Last status from Disk= I/O + =20 + struct fsw_volume *vol; //!< FSW volume structure + =20 +} FSW_VOLUME_DATA; + +/** Signature for the volume structure. */ +#define FSW_VOLUME_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'V') +/** Access macro for the volume structure. */ +#define FSW_VOLUME_FROM_FILE_SYSTEM(a) CR (a, FSW_VOLUME_DATA, FileSystem= , FSW_VOLUME_DATA_SIGNATURE) + +/** + * EFI Host: Private structure for a EFI_FILE interface. + */ + +typedef struct { + UINT64 Signature; //!< Used to identify this= structure + =20 + EFI_FILE FileHandle; //!< Published EFI protoco= l interface structure + =20 + UINTN Type; //!< File type used for di= spatchinng + struct fsw_shandle shand; //!< FSW handle for this f= ile + =20 +} FSW_FILE_DATA; + +/** File type: regular file. */ +#define FSW_EFI_FILE_TYPE_FILE (0) +/** File type: directory. */ +#define FSW_EFI_FILE_TYPE_DIR (1) + +/** Signature for the file handle structure. */ +#define FSW_FILE_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'F') +/** Access macro for the file handle structure. */ +#define FSW_FILE_FROM_FILE_HANDLE(a) CR (a, FSW_FILE_DATA, FileHandle, FS= W_FILE_DATA_SIGNATURE) + + +// +// Library functions +// + +VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime); + +UINTN fsw_efi_strsize(struct fsw_string *s); +VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src); + + +#endif diff --git a/OvmfPkg/FswHfsPlus/fsw_efi_base.h b/OvmfPkg/FswHfsPlus/fsw_efi= _base.h new file mode 100644 index 0000000..3643b3b --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_efi_base.h @@ -0,0 +1,82 @@ +/** + * \file fsw_efi_base.h + * Base definitions for the EFI host environment. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#ifndef _FSW_EFI_BASE_H_ +#define _FSW_EFI_BASE_H_ + + +#include +#include + +#define FSW_LITTLE_ENDIAN (1) + + +// types, reuse EFI types + +typedef INT8 fsw_s8; +typedef UINT8 fsw_u8; +typedef INT16 fsw_s16; +typedef UINT16 fsw_u16; +typedef INT32 fsw_s32; +typedef UINT32 fsw_u32; +typedef INT64 fsw_s64; +typedef UINT64 fsw_u64; + + +// allocation functions + +#define fsw_alloc(size, ptrptr) (((*(ptrptr) =3D AllocatePool(size)) =3D= =3D NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS) +#define fsw_free(ptr) FreePool(ptr) + +// memory functions + +#define fsw_memzero(dest,size) ZeroMem(dest,size) +#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size) +#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) =3D=3D 0) + +// message printing + +#define FSW_MSGSTR(s) L##s +#define FSW_MSGFUNC Print + +// 64-bit hooks + +#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits)) +#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL) + + +#endif diff --git a/OvmfPkg/FswHfsPlus/fsw_efi_edk2_base.h b/OvmfPkg/FswHfsPlus/fs= w_efi_edk2_base.h new file mode 100644 index 0000000..ca14eb2 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_efi_edk2_base.h @@ -0,0 +1,76 @@ +/** + * \file fsw_efi_edk2_base.h + * Base definitions for the EDK EFI Toolkit environment. + */ +/* + * Copyright (c) 2012 Stefan Agner + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#ifndef _FSW_EFI_EDK2_BASE_H_ +#define _FSW_EFI_EDK2_BASE_H_ +/* + * Here is common declarations for EDK<->EDK2 compatibility + */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# define BS gBS + +# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION +# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO SIZE_OF_EFI_FILE_SYSTE= M_VOLUME_LABEL +# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL +# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d) +# define DivU64x32(x,y,z) DivU64x32((x),(y)) + + +#endif diff --git a/OvmfPkg/FswHfsPlus/fsw_efi_lib.c b/OvmfPkg/FswHfsPlus/fsw_efi_= lib.c new file mode 100644 index 0000000..df1817c --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_efi_lib.c @@ -0,0 +1,129 @@ +/** + * \file fsw_efi_lib.c + * EFI host environment library functions. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#include "fsw_efi.h" + + +// +// time conversion +// +// Adopted from public domain code in FreeBSD libc. +// + +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 + +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY TM_THURSDAY + +#define isleap(y) (((y) % 4) =3D=3D 0 && (((y) % 100) !=3D 0 || ((y) % 400= ) =3D=3D 0)) +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) + +static const int mon_lengths[2][MONSPERYEAR] =3D { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; +static const int year_lengths[2] =3D { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime) +{ + long days, rem; + int y, newy, yleap; + const int *ip; + =20 + ZeroMem(EfiTime, sizeof(EFI_TIME)); + =20 + days =3D UnixTime / SECSPERDAY; + rem =3D UnixTime % SECSPERDAY; + =20 + EfiTime->Hour =3D (int) (rem / SECSPERHOUR); + rem =3D rem % SECSPERHOUR; + EfiTime->Minute =3D (int) (rem / SECSPERMIN); + EfiTime->Second =3D (int) (rem % SECSPERMIN); + =20 + y =3D EPOCH_YEAR; + while (days < 0 || days >=3D (long) year_lengths[yleap =3D isleap(y)])= { + newy =3D y + days / DAYSPERNYEAR; + if (days < 0) + --newy; + days -=3D (newy - y) * DAYSPERNYEAR + + LEAPS_THRU_END_OF(newy - 1) - + LEAPS_THRU_END_OF(y - 1); + y =3D newy; + } + EfiTime->Year =3D y; + ip =3D mon_lengths[yleap]; + for (EfiTime->Month =3D 0; days >=3D (long) ip[EfiTime->Month]; ++(Efi= Time->Month)) + days =3D days - (long) ip[EfiTime->Month]; + EfiTime->Month++; // adjust range to EFI conventions + EfiTime->Day =3D (int) (days + 1); +} + +// +// String functions, used for file and volume info +// + +UINTN fsw_efi_strsize(struct fsw_string *s) +{ + if (s->type =3D=3D FSW_STRING_TYPE_EMPTY) + return sizeof(CHAR16); + return (s->len + 1) * sizeof(CHAR16); +} + +VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src) +{ + if (src->type =3D=3D FSW_STRING_TYPE_EMPTY) { + Dest[0] =3D 0; + } else if (src->type =3D=3D FSW_STRING_TYPE_UTF16) { + CopyMem(Dest, src->data, src->size); + Dest[src->len] =3D 0; + } else { + // TODO: coerce, recurse + Dest[0] =3D 0; + } +} + +// EOF diff --git a/OvmfPkg/FswHfsPlus/fsw_lib.c b/OvmfPkg/FswHfsPlus/fsw_lib.c new file mode 100644 index 0000000..abb9062 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_lib.c @@ -0,0 +1,294 @@ +/** + * \file fsw_lib.c + * Core file system wrapper library functions. + */ + +/*- + * Copyright (c) 2006 Christoph Pfisterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of Christoph Pfisterer nor the names of the + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + */ + +#include "fsw_core.h" + +/* Include generated string encoding specific functions */ +#include "fsw_strfunc.h" + + +/** + * Allocate memory and clear it. + */ + +fsw_status_t fsw_alloc_zero(int len, void **ptr_out) +{ + fsw_status_t status; + =20 + status =3D fsw_alloc(len, ptr_out); + if (status) + return status; + fsw_memzero(*ptr_out, len); + return FSW_SUCCESS; +} + +/** + * Duplicate a piece of data. + */ + +fsw_status_t fsw_memdup(void **dest_out, void *src, int len) +{ + fsw_status_t status; + =20 + status =3D fsw_alloc(len, dest_out); + if (status) + return status; + fsw_memcpy(*dest_out, src, len); + return FSW_SUCCESS; +} + +/** + * Get the length of a string. Returns the number of characters in the str= ing. + */ + +int fsw_strlen(struct fsw_string *s) +{ + if (s->type =3D=3D FSW_STRING_TYPE_EMPTY) + return 0; + return s->len; +} + +/** + * Compare two strings for equality. The two strings are compared, taking = their + * encoding into account. If they are considered equal, boolean true is re= turned. + * Otherwise, boolean false is returned. + */ + +int fsw_streq(struct fsw_string *s1, struct fsw_string *s2) +{ + struct fsw_string temp_s; + =20 + // handle empty strings + if (s1->type =3D=3D FSW_STRING_TYPE_EMPTY) { + temp_s.type =3D FSW_STRING_TYPE_ISO88591; + temp_s.size =3D temp_s.len =3D 0; + temp_s.data =3D NULL; + return fsw_streq(&temp_s, s2); + } + if (s2->type =3D=3D FSW_STRING_TYPE_EMPTY) { + temp_s.type =3D FSW_STRING_TYPE_ISO88591; + temp_s.size =3D temp_s.len =3D 0; + temp_s.data =3D NULL; + return fsw_streq(s1, &temp_s); + } + =20 + // check length (count of chars) + if (s1->len !=3D s2->len) + return 0; + if (s1->len =3D=3D 0) // both strings are empty + return 1; + =20 + if (s1->type =3D=3D s2->type) { + // same type, do a dumb memory compare + if (s1->size !=3D s2->size) + return 0; + return fsw_memeq(s1->data, s2->data, s1->size); + } + =20 + // dispatch to type-specific functions + #define STREQ_DISPATCH(type1, type2) \ + if (s1->type =3D=3D FSW_STRING_TYPE_##type1 && s2->type =3D=3D FSW_S= TRING_TYPE_##type2) \ + return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \ + if (s2->type =3D=3D FSW_STRING_TYPE_##type1 && s1->type =3D=3D FSW_S= TRING_TYPE_##type2) \ + return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len); + STREQ_DISPATCH(ISO88591, UTF8); + STREQ_DISPATCH(ISO88591, UTF16); + STREQ_DISPATCH(ISO88591, UTF16_SWAPPED); + STREQ_DISPATCH(UTF8, UTF16); + STREQ_DISPATCH(UTF8, UTF16_SWAPPED); + STREQ_DISPATCH(UTF16, UTF16_SWAPPED); + =20 + // final fallback + return 0; +} + +/** + * Compare a string with a C string constant. This sets up a string descri= ptor + * for the string constant (second argument) and runs fsw_streq on the two + * strings. Currently the C string is interpreted as ISO 8859-1. + * Returns boolean true if the strings are considered equal, boolean false= otherwise. + */ + +int fsw_streq_cstr(struct fsw_string *s1, const char *s2) +{ + struct fsw_string temp_s; + int i; + =20 + for (i =3D 0; s2[i]; i++) + ; + =20 + temp_s.type =3D FSW_STRING_TYPE_ISO88591; + temp_s.size =3D temp_s.len =3D i; + temp_s.data =3D (char *)s2; + =20 + return fsw_streq(s1, &temp_s); +} + +/** + * Creates a duplicate of a string, converting it to the given encoding du= ring the copy. + * If the function returns FSW_SUCCESS, the caller must free the string la= ter with + * fsw_strfree. + */ + +fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct f= sw_string *src) +{ + fsw_status_t status; + =20 + if (src->type =3D=3D FSW_STRING_TYPE_EMPTY || src->len =3D=3D 0) { + dest->type =3D type; + dest->size =3D dest->len =3D 0; + dest->data =3D NULL; + return FSW_SUCCESS; + } + =20 + if (src->type =3D=3D type) { + dest->type =3D type; + dest->len =3D src->len; + dest->size =3D src->size; + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + fsw_memcpy(dest->data, src->data, dest->size); + return FSW_SUCCESS; + } + =20 + // dispatch to type-specific functions + #define STRCOERCE_DISPATCH(type1, type2) \ + if (src->type =3D=3D FSW_STRING_TYPE_##type1 && type =3D=3D FSW_STRI= NG_TYPE_##type2) \ + return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest); + STRCOERCE_DISPATCH(UTF8, ISO88591); + STRCOERCE_DISPATCH(UTF16, ISO88591); + STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591); + STRCOERCE_DISPATCH(ISO88591, UTF8); + STRCOERCE_DISPATCH(UTF16, UTF8); + STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8); + STRCOERCE_DISPATCH(ISO88591, UTF16); + STRCOERCE_DISPATCH(UTF8, UTF16); + STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16); + =20 + return FSW_UNSUPPORTED; +} + +/** + * Splits a string at the first occurence of the separator character. + * The buffer string is searched for the separator character. If it is fou= nd, the + * element string descriptor is filled to point at the part of the buffer = string + * before the separator. The buffer string itself is adjusted to point at = the + * remaining part of the string (without the separator). + * + * If the separator is not found in the buffer string, then element is cha= nged to + * point at the whole buffer string, and the buffer string itself is chang= ed into + * an empty string. + * + * This function only manipulates the pointers and lengths in the two stri= ng descriptors, + * it does not change the actual string. If the buffer string is dynamical= ly allocated, + * you must make a copy of it so that you can release it later. + */ + +void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, c= har separator) +{ + int i, maxlen; + =20 + if (buffer->type =3D=3D FSW_STRING_TYPE_EMPTY || buffer->len =3D=3D 0)= { + element->type =3D FSW_STRING_TYPE_EMPTY; + return; + } + =20 + maxlen =3D buffer->len; + *element =3D *buffer; + =20 + if (buffer->type =3D=3D FSW_STRING_TYPE_ISO88591) { + fsw_u8 *p; + =20 + p =3D (fsw_u8 *)element->data; + for (i =3D 0; i < maxlen; i++, p++) { + if (*p =3D=3D separator) { + buffer->data =3D p + 1; + buffer->len -=3D i + 1; + break; + } + } + element->len =3D i; + if (i =3D=3D maxlen) { + buffer->data =3D p; + buffer->len -=3D i; + } + =20 + element->size =3D element->len; + buffer->size =3D buffer->len; + =20 + } else if (buffer->type =3D=3D FSW_STRING_TYPE_UTF16) { + fsw_u16 *p; + =20 + p =3D (fsw_u16 *)element->data; + for (i =3D 0; i < maxlen; i++, p++) { + if (*p =3D=3D separator) { + buffer->data =3D p + 1; + buffer->len -=3D i + 1; + break; + } + } + element->len =3D i; + if (i =3D=3D maxlen) { + buffer->data =3D p; + buffer->len -=3D i; + } + =20 + element->size =3D element->len * sizeof(fsw_u16); + buffer->size =3D buffer->len * sizeof(fsw_u16); + =20 + } else { + // fallback + buffer->type =3D FSW_STRING_TYPE_EMPTY; + } + =20 + // TODO: support UTF8 and UTF16_SWAPPED +} + +/** + * Frees the memory used by a string returned from fsw_strdup_coerce. + */ + +void fsw_strfree(struct fsw_string *s) +{ + if (s->type !=3D FSW_STRING_TYPE_EMPTY && s->data) + fsw_free(s->data); + s->type =3D FSW_STRING_TYPE_EMPTY; +} + +// EOF diff --git a/OvmfPkg/FswHfsPlus/fsw_strfunc.h b/OvmfPkg/FswHfsPlus/fsw_strf= unc.h new file mode 100644 index 0000000..bc37415 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_strfunc.h @@ -0,0 +1,453 @@ +/* fsw_strfunc.h generated by mk_fsw_strfunc.py */ + +static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 =3D (fsw_u8 *)s1data; + fsw_u8 *p2 =3D (fsw_u8 *)s2data; + fsw_u32 c1, c2; + =20 + for (i =3D 0; i < len; i++) { + c1 =3D *p1++; + c2 =3D *p2++; + if ((c2 & 0xe0) =3D=3D 0xc0) { + c2 =3D ((c2 & 0x1f) << 6) | (*p2++ & 0x3f); + } else if ((c2 & 0xf0) =3D=3D 0xe0) { + c2 =3D ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6); + c2 |=3D (*p2++ & 0x3f); + } else if ((c2 & 0xf8) =3D=3D 0xf0) { + c2 =3D ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12); + c2 |=3D ((*p2++ & 0x3f) << 6); + c2 |=3D (*p2++ & 0x3f); + } + if (c1 !=3D c2) + return 0; + } + return 1; +} + +static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 =3D (fsw_u8 *)s1data; + fsw_u16 *p2 =3D (fsw_u16 *)s2data; + fsw_u32 c1, c2; + =20 + for (i =3D 0; i < len; i++) { + c1 =3D *p1++; + c2 =3D *p2++; + if (c1 !=3D c2) + return 0; + } + return 1; +} + +static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, in= t len) +{ + int i; + fsw_u8 *p1 =3D (fsw_u8 *)s1data; + fsw_u16 *p2 =3D (fsw_u16 *)s2data; + fsw_u32 c1, c2; + =20 + for (i =3D 0; i < len; i++) { + c1 =3D *p1++; + c2 =3D *p2++; c2 =3D FSW_SWAPVALUE_U16(c2); + if (c1 !=3D c2) + return 0; + } + return 1; +} + +static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len) +{ + int i; + fsw_u8 *p1 =3D (fsw_u8 *)s1data; + fsw_u16 *p2 =3D (fsw_u16 *)s2data; + fsw_u32 c1, c2; + =20 + for (i =3D 0; i < len; i++) { + c1 =3D *p1++; + if ((c1 & 0xe0) =3D=3D 0xc0) { + c1 =3D ((c1 & 0x1f) << 6) | (*p1++ & 0x3f); + } else if ((c1 & 0xf0) =3D=3D 0xe0) { + c1 =3D ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6); + c1 |=3D (*p1++ & 0x3f); + } else if ((c1 & 0xf8) =3D=3D 0xf0) { + c1 =3D ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12); + c1 |=3D ((*p1++ & 0x3f) << 6); + c1 |=3D (*p1++ & 0x3f); + } + c2 =3D *p2++; + if (c1 !=3D c2) + return 0; + } + return 1; +} + +static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int le= n) +{ + int i; + fsw_u8 *p1 =3D (fsw_u8 *)s1data; + fsw_u16 *p2 =3D (fsw_u16 *)s2data; + fsw_u32 c1, c2; + =20 + for (i =3D 0; i < len; i++) { + c1 =3D *p1++; + if ((c1 & 0xe0) =3D=3D 0xc0) { + c1 =3D ((c1 & 0x1f) << 6) | (*p1++ & 0x3f); + } else if ((c1 & 0xf0) =3D=3D 0xe0) { + c1 =3D ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6); + c1 |=3D (*p1++ & 0x3f); + } else if ((c1 & 0xf8) =3D=3D 0xf0) { + c1 =3D ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12); + c1 |=3D ((*p1++ & 0x3f) << 6); + c1 |=3D (*p1++ & 0x3f); + } + c2 =3D *p2++; c2 =3D FSW_SWAPVALUE_U16(c2); + if (c1 !=3D c2) + return 0; + } + return 1; +} + +static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int l= en) +{ + int i; + fsw_u16 *p1 =3D (fsw_u16 *)s1data; + fsw_u16 *p2 =3D (fsw_u16 *)s2data; + fsw_u32 c1, c2; + =20 + for (i =3D 0; i < len; i++) { + c1 =3D *p1++; + c2 =3D *p2++; c2 =3D FSW_SWAPVALUE_U16(c2); + if (c1 !=3D c2) + return 0; + } + return 1; +} + +static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen,= struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u8 *sp; + fsw_u8 *dp; + fsw_u32 c; + =20 + dest->type =3D FSW_STRING_TYPE_ISO88591; + dest->len =3D srclen; + dest->size =3D srclen * sizeof(fsw_u8); + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u8 *)srcdata; + dp =3D (fsw_u8 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + if ((c & 0xe0) =3D=3D 0xc0) { + c =3D ((c & 0x1f) << 6) | (*sp++ & 0x3f); + } else if ((c & 0xf0) =3D=3D 0xe0) { + c =3D ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6); + c |=3D (*sp++ & 0x3f); + } else if ((c & 0xf8) =3D=3D 0xf0) { + c =3D ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12); + c |=3D ((*sp++ & 0x3f) << 6); + c |=3D (*sp++ & 0x3f); + } + *dp++ =3D c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen= , struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + =20 + dest->type =3D FSW_STRING_TYPE_ISO88591; + dest->len =3D srclen; + dest->size =3D srclen * sizeof(fsw_u8); + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u16 *)srcdata; + dp =3D (fsw_u8 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + *dp++ =3D c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, in= t srclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + =20 + dest->type =3D FSW_STRING_TYPE_ISO88591; + dest->len =3D srclen; + dest->size =3D srclen * sizeof(fsw_u8); + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u16 *)srcdata; + dp =3D (fsw_u8 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; c =3D FSW_SWAPVALUE_U16(c); + *dp++ =3D c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen= , struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u8 *sp; + fsw_u16 *dp; + fsw_u32 c; + =20 + dest->type =3D FSW_STRING_TYPE_UTF16; + dest->len =3D srclen; + dest->size =3D srclen * sizeof(fsw_u16); + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u8 *)srcdata; + dp =3D (fsw_u16 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + *dp++ =3D c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, st= ruct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u8 *sp; + fsw_u16 *dp; + fsw_u32 c; + =20 + dest->type =3D FSW_STRING_TYPE_UTF16; + dest->len =3D srclen; + dest->size =3D srclen * sizeof(fsw_u16); + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u8 *)srcdata; + dp =3D (fsw_u16 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + if ((c & 0xe0) =3D=3D 0xc0) { + c =3D ((c & 0x1f) << 6) | (*sp++ & 0x3f); + } else if ((c & 0xf0) =3D=3D 0xe0) { + c =3D ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6); + c |=3D (*sp++ & 0x3f); + } else if ((c & 0xf8) =3D=3D 0xf0) { + c =3D ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12); + c |=3D ((*sp++ & 0x3f) << 6); + c |=3D (*sp++ & 0x3f); + } + *dp++ =3D c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int s= rclen, struct fsw_string *dest) +{ + fsw_status_t status; + int i; + fsw_u16 *sp; + fsw_u16 *dp; + fsw_u32 c; + =20 + dest->type =3D FSW_STRING_TYPE_UTF16; + dest->len =3D srclen; + dest->size =3D srclen * sizeof(fsw_u16); + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u16 *)srcdata; + dp =3D (fsw_u16 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; c =3D FSW_SWAPVALUE_U16(c); + *dp++ =3D c; + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen,= struct fsw_string *dest) +{ + fsw_status_t status; + int i, destsize; + fsw_u8 *sp; + fsw_u8 *dp; + fsw_u32 c; + =20 + sp =3D (fsw_u8 *)srcdata; + destsize =3D 0; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + =20 + if (c < 0x000080) + destsize++; + else if (c < 0x000800) + destsize +=3D 2; + else if (c < 0x010000) + destsize +=3D 3; + else + destsize +=3D 4; + } + =20 + dest->type =3D FSW_STRING_TYPE_UTF8; + dest->len =3D srclen; + dest->size =3D destsize; + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u8 *)srcdata; + dp =3D (fsw_u8 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + =20 + if (c < 0x000080) { + *dp++ =3D c; + } else if (c < 0x000800) { + *dp++ =3D 0xc0 | ((c >> 6) & 0x1f); + *dp++ =3D 0x80 | (c & 0x3f); + } else if (c < 0x010000) { + *dp++ =3D 0xe0 | ((c >> 12) & 0x0f); + *dp++ =3D 0x80 | ((c >> 6) & 0x3f); + *dp++ =3D 0x80 | (c & 0x3f); + } else { + *dp++ =3D 0xf0 | ((c >> 18) & 0x07); + *dp++ =3D 0x80 | ((c >> 12) & 0x3f); + *dp++ =3D 0x80 | ((c >> 6) & 0x3f); + *dp++ =3D 0x80 | (c & 0x3f); + } + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, st= ruct fsw_string *dest) +{ + fsw_status_t status; + int i, destsize; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + =20 + sp =3D (fsw_u16 *)srcdata; + destsize =3D 0; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + =20 + if (c < 0x000080) + destsize++; + else if (c < 0x000800) + destsize +=3D 2; + else if (c < 0x010000) + destsize +=3D 3; + else + destsize +=3D 4; + } + =20 + dest->type =3D FSW_STRING_TYPE_UTF8; + dest->len =3D srclen; + dest->size =3D destsize; + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u16 *)srcdata; + dp =3D (fsw_u8 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; + =20 + if (c < 0x000080) { + *dp++ =3D c; + } else if (c < 0x000800) { + *dp++ =3D 0xc0 | ((c >> 6) & 0x1f); + *dp++ =3D 0x80 | (c & 0x3f); + } else if (c < 0x010000) { + *dp++ =3D 0xe0 | ((c >> 12) & 0x0f); + *dp++ =3D 0x80 | ((c >> 6) & 0x3f); + *dp++ =3D 0x80 | (c & 0x3f); + } else { + *dp++ =3D 0xf0 | ((c >> 18) & 0x07); + *dp++ =3D 0x80 | ((c >> 12) & 0x3f); + *dp++ =3D 0x80 | ((c >> 6) & 0x3f); + *dp++ =3D 0x80 | (c & 0x3f); + } + } + return FSW_SUCCESS; +} + +static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int sr= clen, struct fsw_string *dest) +{ + fsw_status_t status; + int i, destsize; + fsw_u16 *sp; + fsw_u8 *dp; + fsw_u32 c; + =20 + sp =3D (fsw_u16 *)srcdata; + destsize =3D 0; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; c =3D FSW_SWAPVALUE_U16(c); + =20 + if (c < 0x000080) + destsize++; + else if (c < 0x000800) + destsize +=3D 2; + else if (c < 0x010000) + destsize +=3D 3; + else + destsize +=3D 4; + } + =20 + dest->type =3D FSW_STRING_TYPE_UTF8; + dest->len =3D srclen; + dest->size =3D destsize; + status =3D fsw_alloc(dest->size, &dest->data); + if (status) + return status; + =20 + sp =3D (fsw_u16 *)srcdata; + dp =3D (fsw_u8 *)dest->data; + for (i =3D 0; i < srclen; i++) { + c =3D *sp++; c =3D FSW_SWAPVALUE_U16(c); + =20 + if (c < 0x000080) { + *dp++ =3D c; + } else if (c < 0x000800) { + *dp++ =3D 0xc0 | ((c >> 6) & 0x1f); + *dp++ =3D 0x80 | (c & 0x3f); + } else if (c < 0x010000) { + *dp++ =3D 0xe0 | ((c >> 12) & 0x0f); + *dp++ =3D 0x80 | ((c >> 6) & 0x3f); + *dp++ =3D 0x80 | (c & 0x3f); + } else { + *dp++ =3D 0xf0 | ((c >> 18) & 0x07); + *dp++ =3D 0x80 | ((c >> 12) & 0x3f); + *dp++ =3D 0x80 | ((c >> 6) & 0x3f); + *dp++ =3D 0x80 | (c & 0x3f); + } + } + return FSW_SUCCESS; +} --=20 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel From nobody Mon Apr 29 08:09:50 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1488856477639771.4036316976789; Mon, 6 Mar 2017 19:14:37 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 7ED648034C; Mon, 6 Mar 2017 19:14:35 -0800 (PST) Received: from mail-qk0-x241.google.com (mail-qk0-x241.google.com [IPv6:2607:f8b0:400d:c09::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id B276C80347 for ; Mon, 6 Mar 2017 19:14:34 -0800 (PST) Received: by mail-qk0-x241.google.com with SMTP id o135so8866576qke.2 for ; Mon, 06 Mar 2017 19:14:34 -0800 (PST) Received: from foober.ini.cmu.edu (pool-108-39-248-175.pitbpa.fios.verizon.net. [108.39.248.175]) by smtp.gmail.com with ESMTPSA id v26sm2901013qtc.13.2017.03.06.19.14.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 19:14:33 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VFuRPx3NFwuMbXVJqYrZzkSXCE7Vu8r8bNhZdVd9TlY=; b=F5Fl5cCGWAXBZAv/pO73LbiVVWj6DEK11FJ+F67DedoWiELluzGl6UIlO0FK8AMWmy cQe3vTstGk/xpqwid/UZqj0Ir7BiidYTFEqOQysw2pYEuX8KSvpUei9gX8E3XAJtw39V mF6GkY6mw3v2cI+ng3h8hHKaNjMhvvkZJoe6c3k1Qsz03HiGX9GgfhV5W9LFpl5JFwzA yyJ0xoHawkp5sfEeACGt/CRLaTGZVoBjI6gb1OvqtojgVSKe1mPrOGGYoBRHb0RKeTXd HNARSI0kAUtcvTKS8kx+5lsVLmwgCK4Top4AAGl0D+v8trdospNMN20+8dstldjN9F6h f8mQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VFuRPx3NFwuMbXVJqYrZzkSXCE7Vu8r8bNhZdVd9TlY=; b=DQa96QvGcyfUtfYadqKbgxzynBeDhB8I6e6gpPJ5vDAQQ6UAVkY+wXB05oahgNe6aF 0KGb4e8DU4hed6WFjGzHSoVzj4HDIlV018UVe/trKMQDgQIgnfbDerP1RS+OJcf27H75 X7xr2WksQE3DCDwDfJwHQeAnOsqarCwKtBapJ+psGYE5+6jO/Qu6/nScMZqEcCmlVkJ+ BwrYQ17FuLgvEZQa7ntYB9spxlJMBopgDkkMlk6XMne8sKgs5Sw5RxlqQOydI41LGbIF plFzjnG3e35kxvZvpdhcL6cOSPBXtgqAAQBc+L7bRH8K+IMGEEi8XewURp0o4AsSfNHv 0iUg== X-Gm-Message-State: AMke39ketS2Uj7dPTc1tGyfhuYp+zQxfVg3AZ2XgF9db2qWd9VFELMGh8BfK3wm1TpMhFw== X-Received: by 10.200.56.210 with SMTP id g18mr18236769qtc.63.1488856473890; Mon, 06 Mar 2017 19:14:33 -0800 (PST) From: "Gabriel L. Somlo" To: edk2-devel@ml01.01.org Date: Mon, 6 Mar 2017 22:14:21 -0500 Message-Id: <1488856465-8965-3-git-send-email-gsomlo@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> References: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> Subject: [edk2] [RFC PATCH 2/6] FswHfsPlus: connect FSW code to EDK2, fix compile discrepancies X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jordan.l.justen@intel.com, lersek@redhat.com, agraf@suse.de MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Connect FSW to EDK2: - in fsw_efi_base.h, s/efi[lib].h/fsw_efi_edk2_base.h/ Fix compile discrepancies: - Fix FSW_INVALID_BNO, FSW_EFI_STRINGIFY macros - Remove EFI_DRIVER_ENTRY_POINT, InitializeLib() call - use correct protocol name GUIDs (gEfiGuid) - edk2's CompareGuid returns TRUE on equal, not 0 like gnu-efi Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Gabriel Somlo --- OvmfPkg/FswHfsPlus/fsw_core.h | 2 +- OvmfPkg/FswHfsPlus/fsw_efi.c | 36 ++++++++++++++++-------------------- OvmfPkg/FswHfsPlus/fsw_efi_base.h | 3 +-- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/OvmfPkg/FswHfsPlus/fsw_core.h b/OvmfPkg/FswHfsPlus/fsw_core.h index 0041ce1..a611b19 100644 --- a/OvmfPkg/FswHfsPlus/fsw_core.h +++ b/OvmfPkg/FswHfsPlus/fsw_core.h @@ -52,7 +52,7 @@ #define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table) =20 /** Indicates that the block cache entry is empty. */ -#define FSW_INVALID_BNO (~0UL) +#define FSW_INVALID_BNO (~0U) =20 =20 // diff --git a/OvmfPkg/FswHfsPlus/fsw_efi.c b/OvmfPkg/FswHfsPlus/fsw_efi.c index c024162..d2b53a7 100644 --- a/OvmfPkg/FswHfsPlus/fsw_efi.c +++ b/OvmfPkg/FswHfsPlus/fsw_efi.c @@ -46,7 +46,7 @@ #endif =20 /** Helper macro for stringification. */ -#define FSW_EFI_STRINGIFY(x) L#x +#define FSW_EFI_STRINGIFY(x) #x /** Expands to the EFI driver name given the file system type name. */ #define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System= Driver" =20 @@ -149,8 +149,6 @@ struct fsw_host_table fsw_efi_host_table =3D { extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE); =20 =20 -EFI_DRIVER_ENTRY_POINT(fsw_efi_main) - /** * Image entry point. Installs the Driver Binding and Component Name proto= cols * on the image's handle. Actually mounting a file system is initiated thr= ough @@ -162,14 +160,12 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE = ImageHandle, { EFI_STATUS Status; =20 - InitializeLib(ImageHandle, SystemTable); - =20 // complete Driver Binding protocol instance fsw_efi_DriverBinding_table.ImageHandle =3D ImageHandle; fsw_efi_DriverBinding_table.DriverBindingHandle =3D ImageHandle; // install Driver Binding protocol Status =3D BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.D= riverBindingHandle, - &DriverBindingProtocol, + &gEfiDriverBindingProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_DriverBinding_table); if (EFI_ERROR (Status)) { @@ -178,7 +174,7 @@ EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE Im= ageHandle, =20 // install Component Name protocol Status =3D BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.D= riverBindingHandle, - &ComponentNameProtocol, + &gEfiComponentNameProtocolGuid, EFI_NATIVE_INTERFACE, &fsw_efi_ComponentName_table); if (EFI_ERROR (Status)) { @@ -206,7 +202,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EF= I_DRIVER_BINDING_PROTOCOL =20 // first, open DiskIO Status =3D BS->OpenProtocol(ControllerHandle, - &DiskIoProtocol, + &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, @@ -216,13 +212,13 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN = EFI_DRIVER_BINDING_PROTOCOL =20 // we were just checking, close it again BS->CloseProtocol(ControllerHandle, - &DiskIoProtocol, + &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); =20 // next, check BlockIO without actually opening it Status =3D BS->OpenProtocol(ControllerHandle, - &BlockIoProtocol, + &gEfiBlockIoProtocolGuid, NULL, This->DriverBindingHandle, ControllerHandle, @@ -258,7 +254,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DR= IVER_BINDING_PROTOCOL *T =20 // open consumed protocols Status =3D BS->OpenProtocol(ControllerHandle, - &BlockIoProtocol, + &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, @@ -269,7 +265,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DR= IVER_BINDING_PROTOCOL *T } =20 Status =3D BS->OpenProtocol(ControllerHandle, - &DiskIoProtocol, + &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ControllerHandle, @@ -297,7 +293,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DR= IVER_BINDING_PROTOCOL *T Volume->FileSystem.Revision =3D EFI_FILE_IO_INTERFACE_REVISION; Volume->FileSystem.OpenVolume =3D fsw_efi_FileSystem_OpenVolume; Status =3D BS->InstallMultipleProtocolInterfaces(&ControllerHandle, - &FileSystemProtocol= , &Volume->FileSystem, + &gEfiSimpleFileSyst= emProtocolGuid, &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned = %x\n", Status); @@ -310,7 +306,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DR= IVER_BINDING_PROTOCOL *T FreePool(Volume); =20 BS->CloseProtocol(ControllerHandle, - &DiskIoProtocol, + &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); } @@ -343,7 +339,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DR= IVER_BINDING_PROTOCOL *T =20 // get the installed SimpleFileSystem interface Status =3D BS->OpenProtocol(ControllerHandle, - &FileSystemProtocol, + &gEfiSimpleFileSystemProtocolGuid, (VOID **) &FileSystem, This->DriverBindingHandle, ControllerHandle, @@ -356,7 +352,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DR= IVER_BINDING_PROTOCOL *T =20 // uninstall Simple File System protocol Status =3D BS->UninstallMultipleProtocolInterfaces(ControllerHandle, - &FileSystemProtocol, = &Volume->FileSystem, + &gEfiSimpleFileSystem= ProtocolGuid, &Volume->FileSystem, NULL); if (EFI_ERROR(Status)) { Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x= \n", Status); @@ -373,7 +369,7 @@ EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DR= IVER_BINDING_PROTOCOL *T =20 // close the consumed protocols Status =3D BS->CloseProtocol(ControllerHandle, - &DiskIoProtocol, + &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); =20 @@ -884,14 +880,14 @@ EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *Fi= le, UINTN RequiredSize; struct fsw_volume_stat vsb; =20 - if (CompareGuid(InformationType, &GenericFileInfo) =3D=3D 0) { + if (CompareGuid(InformationType, &gEfiFileInfoGuid)) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n"); #endif =20 Status =3D fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, = BufferSize, Buffer); =20 - } else if (CompareGuid(InformationType, &FileSystemInfo) =3D=3D 0) { + } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n"); #endif @@ -922,7 +918,7 @@ EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File, *BufferSize =3D RequiredSize; Status =3D EFI_SUCCESS; =20 - } else if (CompareGuid(InformationType, &FileSystemVolumeLabelInfo) = =3D=3D 0) { + } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfo= IdGuid)) { #if DEBUG_LEVEL Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n"); #endif diff --git a/OvmfPkg/FswHfsPlus/fsw_efi_base.h b/OvmfPkg/FswHfsPlus/fsw_efi= _base.h index 3643b3b..5884b92 100644 --- a/OvmfPkg/FswHfsPlus/fsw_efi_base.h +++ b/OvmfPkg/FswHfsPlus/fsw_efi_base.h @@ -39,8 +39,7 @@ #define _FSW_EFI_BASE_H_ =20 =20 -#include -#include +#include "fsw_efi_edk2_base.h" =20 #define FSW_LITTLE_ENDIAN (1) =20 --=20 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel From nobody Mon Apr 29 08:09:50 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1488856482297191.59244301773504; Mon, 6 Mar 2017 19:14:42 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 082E680353; Mon, 6 Mar 2017 19:14:38 -0800 (PST) Received: from mail-qk0-x244.google.com (mail-qk0-x244.google.com [IPv6:2607:f8b0:400d:c09::244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 30F7C8034F for ; Mon, 6 Mar 2017 19:14:36 -0800 (PST) Received: by mail-qk0-x244.google.com with SMTP id n141so25731482qke.3 for ; Mon, 06 Mar 2017 19:14:36 -0800 (PST) Received: from foober.ini.cmu.edu (pool-108-39-248-175.pitbpa.fios.verizon.net. [108.39.248.175]) by smtp.gmail.com with ESMTPSA id v26sm2901013qtc.13.2017.03.06.19.14.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 19:14:34 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=LpB4pNoW0dhKWasMJlYa9GNAhcDV98a8NklsaMI54r0=; b=GJ5CInTttmT6knpqgrrrPI3or/U2DXt7L92Wvn2TQl6Q2hIgBO40KiInFeOuHdINUc Y5Zyk9e01BCwgcr1h1oMyj4hM+qIzJ1MDkHqe0w8MiwxtL2QyWOC+Z9CjtFVabKezqkL gDzi3fZK3qqRI8ByV9XQ+ID+2GbZrP+Wm1iZZhYJksUe396BPyzogW2sk7nmMyCCQ0Au xc7+Tjn4i1QT0aaSAGm1h/WZJMibUfiF5CzQh/Md9N1iuxB4UWkoSZ5uHbnmVMheNrFn KfLGLwBez/NcXJ3zhQxcibSvLczROIswmgceioIXeJZ0zWRJ7K0WngleVmpcODh1v4ly tpoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=LpB4pNoW0dhKWasMJlYa9GNAhcDV98a8NklsaMI54r0=; b=kNygLE5nGNx5vALfXmQCCjS7V3oZDrRtDpskg5C5bTyEzpnEbXPdn+5m5GaR7D0BY0 KZ3rbOI5cQGlqg/G8V5UOJPdR9kWrJxQ1/XTNQjkk0JAzLMYqOsdfo6qIZmC70J4IJsu VSwIJJwiHGPgR/miZ0MJMT6+6tpYP8YBQ/UXWBBh0KCOIsAMVN929ARVQvEJag6qzDn9 sLcGLqStpg0d+xBTQSELop+lSYnej1eV+T5XyN6BC3Y6cidMezvg9U+kt9V8NIG+4xJ7 Z0zK7vNZ/D0hut1Yj2v9Joj43DO19xhvo5HOvbAkV5cuhrOEOx0bYazlwbtlmkJH/gMz 4dMw== X-Gm-Message-State: AMke39l2JSRBXououg8yPbTOcl0CHFN9XNUepj174uGrd/fgIKQ7cQkZuaeDldkvMnsIQA== X-Received: by 10.200.41.42 with SMTP id y39mr18492879qty.37.1488856474738; Mon, 06 Mar 2017 19:14:34 -0800 (PST) From: "Gabriel L. Somlo" To: edk2-devel@ml01.01.org Date: Mon, 6 Mar 2017 22:14:22 -0500 Message-Id: <1488856465-8965-4-git-send-email-gsomlo@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> References: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> Subject: [edk2] [RFC PATCH 3/6] FswHfsPlus: implement FSW driver for the HFS+ file system X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jordan.l.justen@intel.com, lersek@redhat.com, agraf@suse.de MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Implement read-only HFS+ access methods within the FSW framework. Based on the HFS+ Volume Format spec (TN1150), available online at https://developer.apple.com/legacy/library/technotes/tn/tn1150.html Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Gabriel Somlo --- OvmfPkg/FswHfsPlus/FswHfsPlus.inf | 57 ++++ OvmfPkg/FswHfsPlus/fsw_hfsplus.c | 535 ++++++++++++++++++++++++++++++++++= ++++ OvmfPkg/FswHfsPlus/fsw_hfsplus.h | 238 +++++++++++++++++ 3 files changed, 830 insertions(+) create mode 100644 OvmfPkg/FswHfsPlus/FswHfsPlus.inf create mode 100644 OvmfPkg/FswHfsPlus/fsw_hfsplus.c create mode 100644 OvmfPkg/FswHfsPlus/fsw_hfsplus.h diff --git a/OvmfPkg/FswHfsPlus/FswHfsPlus.inf b/OvmfPkg/FswHfsPlus/FswHfsP= lus.inf new file mode 100644 index 0000000..a3581a9 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/FswHfsPlus.inf @@ -0,0 +1,57 @@ +## @file +# File System Wrapper (FSW) based HFS+ driver. +# +# Copyright (C) 2017, Gabriel L. Somlo +# +# This program and the accompanying materials are licensed and made +# available under the terms and conditions of the BSD License which +# accompanies this distribution. The full text of the license may +# be found at http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" +# BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER +# EXPRESS OR IMPLIED. +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D FswHfsPlus + FILE_GUID =3D F474802F-26BB-4E4F-A923-2FC568E94125 + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D fsw_efi_main + +[Sources] + fsw_base.h + fsw_efi_base.h + fsw_efi_edk2_base.h + fsw_strfunc.h + fsw_core.h + fsw_core.c + fsw_efi.h + fsw_efi.c + fsw_lib.c + fsw_efi_lib.c + fsw_hfsplus.h + fsw_hfsplus.c + +[BuildOptions] + GCC:*_*_*_CC_FLAGS =3D -DHOST_EFI -DFSTYPE=3Dhfsplus + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + UefiLib + UefiDriverEntryPoint + +[Guids] + gEfiFileSystemInfoGuid + gEfiFileSystemVolumeLabelInfoIdGuid + gEfiFileInfoGuid + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiDiskIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid diff --git a/OvmfPkg/FswHfsPlus/fsw_hfsplus.c b/OvmfPkg/FswHfsPlus/fsw_hfsp= lus.c new file mode 100644 index 0000000..ef17cc9 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_hfsplus.c @@ -0,0 +1,535 @@ +/** @file + HFS+ file system driver. + + Copyright (C) 2017, Gabriel L. Somlo + + This program and the accompanying materials are licensed and made + available under the terms and conditions of the BSD License which + accompanies this distribution. The full text of the license may + be found at http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER + EXPRESS OR IMPLIED. +**/ + +#include "fsw_hfsplus.h" + + +/* Given dnode 'd' and offset 'pos' into the data file it represents, + * retrieve 'len' bytes of data into buffer 'buf'; + * Return FSW_SUCCESS or error code. + */ +static fsw_status_t +fsw_hfsplus_read(struct fsw_hfsplus_dnode *d, fsw_u64 pos, + fsw_u32 len, void *buf) +{ + struct fsw_shandle sh; + fsw_u32 buflen; + fsw_status_t status; + + status =3D fsw_shandle_open(d, &sh); + if (status) + return status; + + sh.pos =3D pos; + buflen =3D len; + status =3D fsw_shandle_read(&sh, &buflen, buf); + if (!status && buflen !=3D len) + status =3D FSW_IO_ERROR; + + fsw_shandle_close(&sh); + return status; +} + +/* Given the volume being mounted ('v'), and the ID & fork data of the B-T= ree + * file being set up ('dn_id' and 'f', respectively), populate a cached, + * in-memory record of the B-Tree file at the location pointed to by 'btp'; + * Return FSW_SUCCESS or error code. + */ +static fsw_status_t +fsw_hfsplus_btf_setup(struct fsw_hfsplus_volume *v, + fsw_u32 dn_id, HFSPlusForkData *f, + struct fsw_hfsplus_dnode **btp) +{ + BTHeaderRec hdr_rec; + fsw_status_t status; + + status =3D fsw_dnode_create_root(v, dn_id, btp); + if (status) + return status; + + (*btp)->g.size =3D fsw_u64_be_swap(f->logicalSize); + fsw_memcpy((*btp)->extents, f->extents, sizeof(HFSPlusExtentRecord)); + + // read header record (from node 0, immediately past the node descript= or) + status =3D fsw_hfsplus_read(*btp, sizeof(BTNodeDescriptor), + sizeof(BTHeaderRec), &hdr_rec); + if (status) + return status; + + // grab root node index and node size from header record + (*btp)->bt_root =3D fsw_u32_be_swap(hdr_rec.rootNode); + (*btp)->bt_ndsz =3D fsw_u16_be_swap(hdr_rec.nodeSize); + + return FSW_SUCCESS; +} + +/* Mount an HFS+ volume. Read volume header (equivalent of superblock), + * and set up dnodes for the root folder and B-Tree file(s). + * Return FSW_SUCCESS or error code. + */ +static fsw_status_t +fsw_hfsplus_vol_mount(struct fsw_hfsplus_volume *v) +{ + void *buf; + fsw_u32 bs; + fsw_status_t status; + + // allocate memory for vol. header + status =3D fsw_alloc(sizeof(HFSPlusVolumeHeader), &v->vh); + if (status) + return status; + + // read vol. header into buffer + fsw_set_blocksize(v, kHFSBlockSize, kHFSBlockSize); + status =3D fsw_block_get(v, kMasterDirectoryBlock, 0, &buf); + if (status) + return status; + fsw_memcpy(v->vh, buf, sizeof(HFSPlusVolumeHeader)); + fsw_block_release(v, kMasterDirectoryBlock, buf); + + // check vol. header + if (fsw_u16_be_swap(v->vh->signature) !=3D kHFSPlusSigWord) + return FSW_UNSUPPORTED; + + // use block size specified by vol. header + bs =3D fsw_u32_be_swap(v->vh->blockSize); + fsw_set_blocksize(v, bs, bs); + + // set up catalog B-Tree file: + status =3D fsw_hfsplus_btf_setup(v, kHFSCatalogFileID, &v->vh->catalog= File, + &v->catf); + if (status) + return status; + + // set up root folder: + status =3D fsw_dnode_create_root(v, kHFSRootFolderID, &v->g.root); + if (status) + return status; + + return FSW_SUCCESS; +} + +/* Free the volume data structure. Called by the core after an unmount or + * unsuccessful mount, to release the memory used by the file system type + * specific part of the volume structure. + */ +static void +fsw_hfsplus_vol_free(struct fsw_hfsplus_volume *v) +{ + if (v->vh) + fsw_free(v->vh); + if (v->catf) + fsw_dnode_release((struct fsw_dnode *)v->catf); +} + +/* Get in-depth information on a volume. + */ +static fsw_status_t +fsw_hfsplus_vol_stat(struct fsw_hfsplus_volume *v, struct fsw_volume_stat = *s) +{ + // FIXME: not yet supported! + return FSW_UNSUPPORTED; +} + +/* Get full information on a dnode from disk. This function is called by + * the core whenever it needs to access fields in the dnode structure that + * may not be filled immediately upon creation of the dnode. + */ +static fsw_status_t +fsw_hfsplus_dno_fill(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnod= e *d) +{ + // NOTE: not applicable to HFS+ dnodes! + return FSW_SUCCESS; +} + +/* Free the dnode data structure. Called by the core when deallocating a d= node + * structure to release the memory used by the file system type specific p= art + * of the dnode structure. + */ +static void +fsw_hfsplus_dno_free(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnod= e *d) +{ + // NOTE: not applicable to HFS+ dnodes! + return; +} + +/* Get in-depth dnode information. The core ensures fsw_hfsplus_dno_fill() + * has been called on the dnode before this function is called. Note that = some + * data is not directly stored into the structure, but passed to a host-sp= ecific + * callback that converts it to the host-specific format. + */ +static fsw_status_t +fsw_hfsplus_dno_stat(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnod= e *d, + struct fsw_dnode_stat *s) +{ + // FIXME: not yet supported! + return FSW_SUCCESS; +} + +/* Given a B-Tree node pointed to by 'btnode', with node size 'size', + * locate the record given by its record number 'rnum'; + * Return a pointer to the B-Tree key at the beginning of the record. + */ +static HFSPlusBTKey * +fsw_hfsplus_bt_get_rec(BTNodeDescriptor* btnode, fsw_u16 size, fsw_u16 rnu= m) +{ + fsw_u16 *off =3D (fsw_u16 *)((void *)btnode + size) - 1 - rnum; + return (HFSPlusBTKey *)((void *)btnode + fsw_u16_be_swap(*off)); +} + +/* Given a B-Tree record pointer 'k', return a pointer to the data + * immediately following the key record; IOW, skip the key record which + * prefixes the record data payload. + */ +static void * +fsw_hfsplus_bt_rec_skip_key(HFSPlusBTKey *k) +{ + return (void *)k + sizeof(k->keyLength) + fsw_u16_be_swap(k->keyLength= ); +} + +/* Return the child node number immediately following the key record 'k' of + * an index node + */ +static fsw_u32 +fsw_hfsplus_bt_idx_get_child(HFSPlusBTKey *k) +{ + fsw_u32 *child; + child =3D (fsw_u32 *)fsw_hfsplus_bt_rec_skip_key(k); + return fsw_u32_be_swap(*child); +} + +/* key comparison procedure type */ +typedef int (*k_cmp_t)(HFSPlusBTKey*, HFSPlusBTKey*); + +/* Search an HFS+ special file's B-Tree (given by 'bt'), for a search key + * matching 'sk', using comparison procedure 'k_cmp' to determine when a k= ey + * match occurs; Fill a caller-provided B-Tree node buffer ('btnode'), and + * return a pointer to the matching record data inside 'btnode' via 'data_= ptr'; + * On error, set fsw_status_t return code acoordingly. + * + * NOTE: A HFS+ volume has a few "special" files, linked directly from the + * volume header. For the purpose of this driver, we mainly care abo= ut + * two of them: the "catalog" and "extents" files. All of these files + * are organized as B-Tree structures. This means that, overlaid on + * top of the linear span of each file there is an array of nodes of + * a given size (node_size), internally cross-linked with "pointers" + * to parent/child/sibling nodes, which are essentially the "index" + * (or 'node-number') of the target node in this overlaid array. + * Ultimately, (node-number * node-size) is a byte offset into the + * file, to the location where the referenced node's data begins. + * Each B-Tree file's "dnode" information is available in the HFS+ + * volume header. The node at the very beginning of each file (at + * index or node-number =3D=3D 0) contains a "header node", which pr= ovides + * the 'node-number' of the B-Tree's "root" node, as well as the + * 'node-size' of all nodes in that B-Tree file. + */ +static fsw_status_t +fsw_hfsplus_bt_search(struct fsw_hfsplus_dnode *bt, + HFSPlusBTKey *sk, k_cmp_t k_cmp, + BTNodeDescriptor *btnode, void **data_ptr) +{ + fsw_u32 node; + fsw_u16 rec, lo, hi; + HFSPlusBTKey *tk; // trial key + int cmp; + fsw_status_t status; + + // start searching from the B-Tree root node: + node =3D bt->bt_root; + + for (;;) { + // load data for current node into caller-provided buffer 'btnode' + status =3D fsw_hfsplus_read(bt, (fsw_u64)node * bt->bt_ndsz, + bt->bt_ndsz, btnode); + if (status) + return status; + + // sanity check: record 0 located immediately after node descriptor + if ((void *)btnode + sizeof(BTNodeDescriptor) !=3D + (void *)fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, 0)) + return FSW_VOLUME_CORRUPTED; + + // search records within current node + lo =3D 0; + hi =3D fsw_u16_be_swap(btnode->numRecords) - 1; + while (lo <=3D hi) { + // access record data, then compare to search key 'sk' + rec =3D (lo + hi) >> 1; + tk =3D fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, rec); + cmp =3D k_cmp(tk, sk); + + if (cmp < 0) // (tk < sk) + lo =3D rec + 1; + else if (cmp > 0) // (tk > sk) + hi =3D rec - 1; + else { // (tk =3D=3D sk) + if (btnode->kind !=3D kBTLeafNode) { + hi =3D rec; + break; + } + // success: return pointer to data immediately past trial= key + *data_ptr =3D fsw_hfsplus_bt_rec_skip_key(tk); + return FSW_SUCCESS; + } + } + + // NOTE: following the binary search, 'hi' now points at the + // record with the largest 'tk' for which (tk <=3D sk) + + if (btnode->kind !=3D kBTIndexNode) + break; + + // on an index node, so descend to child + tk =3D fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, hi); + node =3D fsw_hfsplus_bt_idx_get_child(tk); + } + + // search key 'sk' not found + return FSW_NOT_FOUND; +} + + +/* Compare unsigned integers 'a' and 'b'; + * Return -1/0/1 if 'a' is less/equal/greater than 'b'. + */ +static int +fsw_hfsplus_int_cmp(fsw_u32 a, fsw_u32 b) +{ + return (a < b) ? -1 : (a > b) ? 1 : 0; +} + +/* Basic latin unicode lowercase + */ +static fsw_u16 +fsw_hfsplus_ucblatin_tolower(fsw_u16 c) +{ + if (c =3D=3D 0) + return 0xFFFF; + if (c =3D=3D 0x00C6 || c =3D=3D 0x00D0 || c =3D=3D 0x00D8 || c =3D=3D = 0x00DE || + (c >=3D 0x0041 && c <=3D 0x005A)) + return c + 0x0020; + return c; + // FIXME: does edk2 have its own built-in function we could use here? +} + +/* Compare an on-disk catalog B-Tree trial key ('tk') with an in-memory + * search key ('sk'). Precedence is parentID, nodeName (keyLength does not + * factor into the comparison). + * Return -1/0/1 if 'tk'is smaller/equal/larger than 'sk', respectively. + * NOTE: all 'tk' fields are stored as big-endian values and must be + * converted to CPU endianness before any comparison to corresponding + * fields in 'sk'. + */ +static int +fsw_hfsplus_cat_cmp(HFSPlusBTKey *tk, HFSPlusBTKey *sk) +{ + fsw_u16 *t_str, *s_str; + fsw_u16 t_len, s_len; + fsw_u16 t_char, s_char; + int ret; + + // compare parent IDs: if unequal, we're done! + ret =3D fsw_hfsplus_int_cmp(fsw_u32_be_swap(tk->catKey.parentID), + sk->catKey.parentID); + if (ret) + return ret; + + // unicode string pointers and lengths: + t_len =3D fsw_u16_be_swap(tk->catKey.nodeName.length); + t_str =3D tk->catKey.nodeName.unicode; + s_len =3D sk->catKey.nodeName.length; + s_str =3D sk->catKey.nodeName.unicode; + + for (;;) { + // start by assuming strings are empty: + t_char =3D s_char =3D 0; + + // find next valid char from on-disk key string: + while (t_char =3D=3D 0 && t_len > 0) { + t_char =3D fsw_hfsplus_ucblatin_tolower(fsw_u16_be_swap(*t_str= )); + t_len--; + t_str++; + } + + // find next valid char from memory key string: + while (s_char =3D=3D 0 && s_len > 0) { + s_char =3D fsw_hfsplus_ucblatin_tolower(*s_str); + s_len--; + s_str++; + } + + // stop if difference or both strings exhausted: + ret =3D fsw_hfsplus_int_cmp(t_char, s_char); + if (ret || s_char =3D=3D 0) + break; + } + + return ret; +} + +/* Retrieve file data mapping information. This function is called by + * the core when fsw_shandle_read needs to know where on the disk the + * required piece of the file's data can be found. The core makes sure + * that fsw_hfsplus_dno_fill has been called on the dnode before. + * Our task here is to get the physical disk block number for the + * requested logical block number. + * NOTE: logical and physical block sizes are the same (see mount method). + */ +static fsw_status_t +fsw_hfsplus_get_ext(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode= *d, + struct fsw_extent *e) +{ + fsw_u32 off, bc; + HFSPlusExtentRecord *er; + int i; + + // set initial offset to provided starting logical block number: + off =3D e->log_start; + + // start with dnode's initial extent record: + er =3D &d->extents; + + // search extent record: + for (i =3D 0; i < kHFSPlusExtentDensity; i++) { + // get block count for current extent descriptor: + bc =3D fsw_u32_be_swap((*er)[i].blockCount); + + // have we exhausted all available extents? + if (bc =3D=3D 0) + return FSW_NOT_FOUND; + + // offset is relative to current extent's physical startBlock: + if (off < bc) { + e->type =3D FSW_EXTENT_TYPE_PHYSBLOCK; + e->phys_start =3D fsw_u32_be_swap((*er)[i].startBlock) + off; + e->log_count =3D bc - off; + return FSW_SUCCESS; + } + + // update offset to NEXT extent descriptor: + off -=3D bc; + } + + // FIXME: more than 8 fragments not yet supported! + return FSW_UNSUPPORTED; +} + + +/* Lookup a directory's child dnode by name. This function is called on a + * directory to retrieve the directory entry with the given name. A dnode + * is constructed for this entry and returned. The core makes sure that + * fsw_hfsplus_dno_fill has been called and the dnode is actually a direct= ory. + */ +static fsw_status_t +fsw_hfsplus_dir_get(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode= *d, + struct fsw_string *name, struct fsw_hfsplus_dnode **d_= out) +{ + BTNodeDescriptor *btnode; + fsw_s16 child_rec_type; + fsw_u32 child_dno_id, child_dno_type; + HFSPlusCatalogKey k; + HFSPlusCatalogRecord *rec; + fsw_status_t status; + + // we only support FSW_STRING_TYPE_UTF16 names: + if (name->type !=3D FSW_STRING_TYPE_UTF16 || + name->size > sizeof(k.nodeName.unicode)) + return FSW_UNSUPPORTED; + + // pre-allocate bt-node buffer for use by search function: + status =3D fsw_alloc(v->catf->bt_ndsz, &btnode); + if (status) + return status; + + // search catalog file for child named by 'name': + k.parentID =3D d->g.dnode_id; + k.nodeName.length =3D name->len; + fsw_memcpy(k.nodeName.unicode, name->data, name->size); + // NOTE: keyLength not used in search, setting only for completeness: + k.keyLength =3D sizeof(k.parentID) + sizeof(k.nodeName.length) + name-= >size; + status =3D fsw_hfsplus_bt_search(v->catf, + (HFSPlusBTKey *)&k, fsw_hfsplus_cat_cmp, + btnode, (void **)&rec); + if (status) + goto done; + + // child record immediately follows the record key data: + child_rec_type =3D fsw_u16_be_swap(rec->recordType); + if (child_rec_type =3D=3D kHFSPlusFolderRecord) { + child_dno_id =3D fsw_u32_be_swap(rec->folderRecord.folderID); + child_dno_type =3D FSW_DNODE_TYPE_DIR; + } else if (child_rec_type =3D=3D kHFSPlusFileRecord) { + child_dno_id =3D fsw_u32_be_swap(rec->fileRecord.fileID); + child_dno_type =3D FSW_DNODE_TYPE_FILE; + } else { + child_dno_id =3D 0; + child_dno_type =3D FSW_DNODE_TYPE_UNKNOWN; + } + status =3D fsw_dnode_create(d, child_dno_id, child_dno_type, name, d_o= ut); + if (status) + goto done; + + // if child node is a file, set size and initial extents: + if (child_rec_type =3D=3D kHFSPlusFileRecord) { + (*d_out)->g.size =3D + fsw_u64_be_swap(rec->fileRecord.dataFork.logicalSize); + fsw_memcpy((*d_out)->extents, &rec->fileRecord.dataFork.extents, + sizeof(HFSPlusExtentRecord)); + } + +done: + fsw_free(btnode); + return status; +} + +/* Get the next directory entry when reading a directory. This function is + * called during directory iteration to retrieve the next directory entry. + * A dnode is constructed for the entry and returned. The core makes sure + * that fsw_hfsplus_dno_fill has been called and the dnode is actually a + * directory. The shandle provided by the caller is used to record the + * position in the directory between calls. + */ +static fsw_status_t +fsw_hfsplus_dir_read(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnod= e *d, + struct fsw_shandle *sh, struct fsw_hfsplus_dnode **d_= out) +{ + // FIXME: not yet supported! + return FSW_UNSUPPORTED; +} + +/* Get the target path of a symbolic link. This function is called when a + * symbolic link needs to be resolved. The core makes sure that the + * fsw_hfsplus_dno_fill has been called on the dnode and that it really is= a + * symlink. + */ +static fsw_status_t +fsw_hfsplus_readlink(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnod= e *d, + struct fsw_string *lnk_tgt) +{ + // FIXME: not yet supported! + return FSW_UNSUPPORTED; +} + + +/* HFS+ FSW Method Dispatch Table + */ +struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfsplus) =3D { + { FSW_STRING_TYPE_ISO88591, 4, 4, "hfsplus" }, + sizeof(struct fsw_hfsplus_volume), sizeof(struct fsw_hfsplus_dnode), + fsw_hfsplus_vol_mount, fsw_hfsplus_vol_free, fsw_hfsplus_vol_stat, + fsw_hfsplus_dno_fill, fsw_hfsplus_dno_free, fsw_hfsplus_dno_stat, + fsw_hfsplus_get_ext, fsw_hfsplus_dir_get, fsw_hfsplus_dir_read, + fsw_hfsplus_readlink, +}; diff --git a/OvmfPkg/FswHfsPlus/fsw_hfsplus.h b/OvmfPkg/FswHfsPlus/fsw_hfsp= lus.h new file mode 100644 index 0000000..38f4631 --- /dev/null +++ b/OvmfPkg/FswHfsPlus/fsw_hfsplus.h @@ -0,0 +1,238 @@ +/** @file + HFS+ file system driver header. + + Copyright (C) 2017, Gabriel L. Somlo + + This program and the accompanying materials are licensed and made + available under the terms and conditions of the BSD License which + accompanies this distribution. The full text of the license may + be found at http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER + EXPRESS OR IMPLIED. +**/ + +#ifndef _FSW_HFSPLUS_H_ +#define _FSW_HFSPLUS_H_ + +#define VOLSTRUCTNAME fsw_hfsplus_volume +#define DNODESTRUCTNAME fsw_hfsplus_dnode +#include "fsw_core.h" + +/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D HFS+ constants and data types fr= om Apple TN1150 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ +#pragma pack(1) + +#define kHFSBlockSize 512 // Minimum block size to transfer Vol= .Hdr. +#define kMasterDirectoryBlock 2 // Vol.Hdr. disk offset (x kHFSBlockS= ize) + +#define kHFSPlusSigWord 0x482B // HFS+ volume signature (ASCII for '= H+') + +#define kHFSPlusMaxFileNameChars 255 // Max. length of HFS+ folder or file= name + +#define kHFSPlusExtentDensity 8 // Number of extent descriptors per r= ecord + +#define kHFSPlusDataFork 0x00 // data fork type +#define kHFSPlusResourceFork 0xFF // resource fork type + +#define kHFSRootFolderID 2 // ID of the root folder +#define kHFSExtentsFileID 3 // ID of the extent overflow file +#define kHFSCatalogFileID 4 // ID of the catalog file + +#define kHFSPlusFolderRecord 1 // catalog folder record type +#define kHFSPlusFileRecord 2 // catalog file record type + +#define kBTLeafNode -1 // B-Tree leaf node type +#define kBTIndexNode 0 // B-Tree index node type +#define kBTHeaderNode 1 // B-Tree header node type + +// file/folder name unicode string type +typedef struct { + fsw_u16 length; // character count + fsw_u16 unicode[kHFSPlusMaxFileNameChars]; // character string +} HFSUniStr255; + +// extent descriptor type +typedef struct { + fsw_u32 startBlock; // first allocation block in the extent + fsw_u32 blockCount; // extent length, in allocation blocks +} HFSPlusExtentDescriptor; + +// extent record type +typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[kHFSPlusExtentDensity]; + +// fork-data information type +typedef struct { + fsw_u64 logicalSize; // size of valid fork data, in bytes + fsw_u32 clumpSize; // fork-specific clump size + fsw_u32 totalBlocks; // total blocks across all extents in= fork + HFSPlusExtentRecord extents; // initial extents for the fork data +} HFSPlusForkData; + +// volume header type +typedef struct { + fsw_u16 signature; // should be kHFSPlusSigWord + fsw_u16 version; // should be kHFSPlusVersion + fsw_u32 attributes; // volume attributes + fsw_u32 lastMountedVersion; // unique ID of software that last wrote v= olume + fsw_u32 journalInfoBlock; // block no. of journal info + fsw_u32 createDate; // volume creation timestamp (date and tim= e) + fsw_u32 modifyDate; // volume last modification timestamp + fsw_u32 backupDate; // timestamp of last backup + fsw_u32 checkedDate; // timestamp of last consistency check + fsw_u32 fileCount; // total number of files on volume + fsw_u32 folderCount; // total number of folders on volume + fsw_u32 blockSize; // allocation block size, in bytes + fsw_u32 totalBlocks; // total number of allocation blocks + fsw_u32 freeBlocks; // total number of unused allocation blocks + fsw_u32 nextAllocation; // block number to start next allocation s= earch + fsw_u32 rsrcClumpSize; // dflt. resource fork clump size (in byte= s) + fsw_u32 dataClumpSize; // dflt. data fork clump size (in bytes) + fsw_u32 nextCatalogID; // next unused catalog ID + fsw_u32 writeCount; // incr. each time volume is write-mounted + fsw_u64 encodingsBitmap; // keep track of text encodings used in na= mes + fsw_u8 finderInfo[32]; // information used by the OS X Finder + HFSPlusForkData allocationFile; // info re. size & location of alloc. = file + HFSPlusForkData extentsFile; // info re. size & location of extents= file + HFSPlusForkData catalogFile; // info re. size & location of catalog= file + HFSPlusForkData attributesFile; // info re. size & location of attr. f= ile + HFSPlusForkData startupFile; // info re. size & location of startup= file +} HFSPlusVolumeHeader; + +// file permissions type +typedef struct { + fsw_u32 ownerID; // owner UID (or hard-link previous-link) + fsw_u32 groupID; // owner GID (or hard-link next-link) + fsw_u8 adminFlags; // flags changeable by root only + fsw_u8 ownerFlags; // flags changeable by owner + fsw_u16 fileMode; // BSD file type and mode bits + union { + fsw_u32 iNodeNum; // link reference number, if hard-link + fsw_u32 linkCount; // ref-count of hard-links, if indirect node fi= le + fsw_u32 rawDevice; // device number, if block/char special dev. fi= le + } special; // reserved for directories and most files +} HFSPlusBSDInfo; + +// finder info types +typedef struct { + fsw_u8 opaque[16]; +} FndrFileInfo, FndrDirInfo, FndrOpaqueInfo; + +// catalog folder record type +typedef struct { + fsw_s16 recordType; // should be kHFSPlusFolderRecord + fsw_u16 flags; // bit flags about the folder (reserved) + fsw_u32 valence; // items directly contained by this folder + fsw_u32 folderID; // CNID of this folder + fsw_u32 createDate; // folder creation timestamp (date and tim= e) + fsw_u32 contentModDate; // folder content last modification timest= amp + fsw_u32 attributeModDate; // ctime (last change to a catalog record = field) + fsw_u32 accessDate; // atime (last access timestamp) + fsw_u32 backupDate; // timestamp of last backup + HFSPlusBSDInfo permissions; // folder permissions + FndrDirInfo userInfo; // information used by the OS X Finder + FndrOpaqueInfo finderInfo; // additional information for the OS X Fin= der + fsw_u32 textEncoding; // hint re. folder name text encoding + fsw_u32 reserved; // reserved field +} HFSPlusCatalogFolder; + +// catalog file record type +typedef struct { + fsw_s16 recordType; // should be kHFSPlusFileRecord + fsw_u16 flags; // bit flags about the file (reserved) + fsw_u32 reserved1; // reserved field + fsw_u32 fileID; // CNID of this file + fsw_u32 createDate; // file creation timestamp (date and time) + fsw_u32 contentModDate; // file content last modification timestamp + fsw_u32 attributeModDate; // ctime (last change to a catalog record = field) + fsw_u32 accessDate; // atime (last access timestamp) + fsw_u32 backupDate; // timestamp of last backup + HFSPlusBSDInfo permissions; // file permissions + FndrFileInfo userInfo; // information used by the OS X Finder + FndrOpaqueInfo finderInfo; // additional information for the OS X Fin= der + fsw_u32 textEncoding; // hint re. file name text encoding + fsw_u32 reserved2; // reserved field + HFSPlusForkData dataFork; // info re. size & location of data fork + HFSPlusForkData resourceFork; // info re. size & location of resource = fork +} HFSPlusCatalogFile; + +// generic (union) catalog record type +typedef union { + fsw_s16 recordType; // set to kHFSPlus[Folder|File]Reco= rd + HFSPlusCatalogFolder folderRecord; // catalog folder record fields + HFSPlusCatalogFile fileRecord; // catalog file record fields +} HFSPlusCatalogRecord; + +// B-Tree node descriptor found at the start of each node +typedef struct { + fsw_u32 fLink; // number of next node of this type (0 if we're la= st) + fsw_u32 bLink; // number of prev. node of this type (0 if we're f= irst) + fsw_s8 kind; // node type (leaf, index, header, map) + fsw_u8 height; // node depth in B-Tree hierarchy (0 for header) + fsw_u16 numRecords; // number of records contained in this node + fsw_u16 reserved; // reserved field +} BTNodeDescriptor; + +// B-Tree header record type (first record of a B-Tree header node) +typedef struct { + fsw_u16 treeDepth; // current B-Tree depth (always =3D=3D rootNod= e.height) + fsw_u32 rootNode; // node number of B-Tree root node + fsw_u32 leafRecords; // total number of records across all leaf nod= es + fsw_u32 firstLeafNode; // node number of first leaf node + fsw_u32 lastLeafNode; // node number of last leaf node + fsw_u16 nodeSize; // node size (in bytes) + fsw_u16 maxKeyLength; // max. length of a key in index/leaf node + fsw_u32 totalNodes; // total number of nodes in the B-Tree + fsw_u32 freeNodes; // number of unused nodes in the B-Tree + fsw_u16 reserved1; // reserved field + fsw_u32 clumpSize; // reserved field (deprecated) + fsw_u8 btreeType; // reserved (0 for catalog, extents, attrib. f= ile) + fsw_u8 keyCompareType; // case-sensitive string comparison (HFSX only) + fsw_u32 attributes; // B-Tree attributes + fsw_u32 reserved3[16]; // reserved field +} BTHeaderRec; + +// extent overflow file key type +typedef struct { + fsw_u16 keyLength; // key length (excluding this field) + fsw_u8 forkType; // data or resource fork + fsw_u8 pad; // ensure 32-bit alignment for subsequent fields + fsw_u32 fileID; // CNID of file to which this extent record applies + fsw_u32 startBlock; // start block of first extent described by this r= ecord +} HFSPlusExtentKey; + +// catalog file key type +typedef struct { + fsw_u16 keyLength; // key length (excluding this field) + fsw_u32 parentID; // ID of parent folder (or CNID if thread reco= rd) + HFSUniStr255 nodeName; // basename of file or folder +} HFSPlusCatalogKey; + +// generic (union) B-Tree record key type +typedef union { + fsw_u16 keyLength; // key length (excluding this field) + HFSPlusExtentKey extKey; // extent key fields + HFSPlusCatalogKey catKey; // catalog key fields +} HFSPlusBTKey; + +#pragma pack() +/*=3D=3D=3D=3D=3D=3D=3D=3D=3D end HFS+ constants and data types from Apple= TN1150 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ + + +// FSW: HFS+ specific dnode +struct fsw_hfsplus_dnode { + struct fsw_dnode g; // Generic (parent) dnode structure + HFSPlusExtentRecord extents; // HFS+ initial extent record + fsw_u32 bt_root; // root node index (if B-Tree file) + fsw_u16 bt_ndsz; // node size (if B-Tree file) +}; + + +// FSW: HFS+ specific volume +struct fsw_hfsplus_volume { + struct fsw_volume g; // Generic (parent) volume structure + HFSPlusVolumeHeader *vh; // Raw HFS+ Volume Header + struct fsw_hfsplus_dnode *catf; // Catalog file dnode +}; + +#endif // _FSW_HFSPLUS_H_ --=20 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel From nobody Mon Apr 29 08:09:50 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1488856479724967.7130101204884; Mon, 6 Mar 2017 19:14:39 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id BC75080350; Mon, 6 Mar 2017 19:14:37 -0800 (PST) Received: from mail-qk0-x241.google.com (mail-qk0-x241.google.com [IPv6:2607:f8b0:400d:c09::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 3959C80350 for ; Mon, 6 Mar 2017 19:14:36 -0800 (PST) Received: by mail-qk0-x241.google.com with SMTP id v125so11260363qkh.1 for ; Mon, 06 Mar 2017 19:14:36 -0800 (PST) Received: from foober.ini.cmu.edu (pool-108-39-248-175.pitbpa.fios.verizon.net. [108.39.248.175]) by smtp.gmail.com with ESMTPSA id v26sm2901013qtc.13.2017.03.06.19.14.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 19:14:35 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PT8jrS05wByoIGkLF8589eBSIErCImhmfKZn9KBd5q4=; b=Ra63V9+M8AEUWRFR+sM+t4zogV/1kSxY5gzjLriIwLbpcdsViDj7xNzVAJxUcAGcLe 2JIsZvvcWxs0JqMKAUsdy92bDUAfwvc5j9WMBdtSUpiVo3V+KawK9ZSRpm+Cv+TpYavP I9W0+c9Tqj5W9Uq7VqsbjfCA6d+zeJlQt2IubM4T04VsF2nSjP3LV2prpE+qmBWfTvW6 xEMntjrfol/beSv1g3yV1EAHB6Ofj8y/BA5arPRRcySgKyjFDE1WWni3cdkz1MN+52Hp tqgh3gmhHgZUJ/vp06x9J4BriJmtckRo+Uiq9HqpuWL54Hl/0XPDM2CxL4Tz56/sonTN Josg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=PT8jrS05wByoIGkLF8589eBSIErCImhmfKZn9KBd5q4=; b=E6ELFUjMTDKpz2kRsTcwlwkLoX3MDWGulL2P1mORCWoxdm/pC80jYaFx4HM2wKuWbv vxxu7vo3wlnAasJyJLsqT/9RvHEeHbcTmvom7PdNts1MzQA02rtskzQhOWfoGuICwn+f iWw8/dtpoP3WxkIYQmSJmvlnXdIF2o8qMaMySWXdPdzhvJt/qVJsqTg/0fijS4r25w/Q RctJb37cz4Vtuwt15vrD2uVbo30XNmDCwBlw74G8MnJ7DrT979+C8wCLflWsbQTFF63h 4JkdqJo76qWPt+i+n6VCvRGMOAchL5umhrNOnlyg6WgggmS6mR5SFNl8ZCSXa8pjg7jt MilA== X-Gm-Message-State: AMke39nNS2nTWNcxBo/vdCRzOl5uqxebGt1agf01q6CKcaxmv684k+LGqt736j9nm2iL3w== X-Received: by 10.55.81.10 with SMTP id f10mr17105471qkb.171.1488856475483; Mon, 06 Mar 2017 19:14:35 -0800 (PST) From: "Gabriel L. Somlo" To: edk2-devel@ml01.01.org Date: Mon, 6 Mar 2017 22:14:23 -0500 Message-Id: <1488856465-8965-5-git-send-email-gsomlo@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> References: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> Subject: [edk2] [RFC PATCH 4/6] EdkCompatibilityPkg: allow ConsoleControl protocol to be used X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jordan.l.justen@intel.com, lersek@redhat.com, agraf@suse.de MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Apple's bootloader requires the ConsoleControl protocol to be implemented. By adding the Foundation path to the package description, the ConsoleProtocol can be used in Ovmf without the need of copying it to Include/Protocol from MdePkg. The gEfiConsoleControlProtocolGuid is added to the .dec file, to be consumed by Ovmf. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Reza Jelveh Signed-off-by: Gabriel Somlo --- EdkCompatibilityPkg/EdkCompatibilityPkg.dec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EdkCompatibilityPkg/EdkCompatibilityPkg.dec b/EdkCompatibility= Pkg/EdkCompatibilityPkg.dec index 1fd1251..0a9225d 100644 --- a/EdkCompatibilityPkg/EdkCompatibilityPkg.dec +++ b/EdkCompatibilityPkg/EdkCompatibilityPkg.dec @@ -25,6 +25,7 @@ =20 [Includes] Compatibility/Include + Foundation =20 [LibraryClasses] ## @libraryclass Provides functions for language conversion between @@ -44,6 +45,7 @@ [Protocols] gEfiPrintProtocolGuid =3D { 0xdf2d868e, 0x32fc, 0x4cf0= , {0x8e, 0x6b, 0xff, 0xd9, 0x5d, 0x13, 0x43, 0xd0} } gEfiSmmBaseHelperReadyProtocolGuid =3D { 0x910dca07, 0x1f94, 0x4ee7= , { 0xaf, 0x2f, 0xff, 0x72, 0xf3, 0x15, 0x43, 0x53 } } + gEfiConsoleControlProtocolGuid =3D { 0xf42f7782, 0x012e, 0x4c12= , {0x99, 0x56, 0x49, 0xf9, 0x43, 0x04, 0xf7, 0x21 }} =20 [PcdsDynamic, PcdsDynamicEx] gEfiEdkCompatibilityPkgTokenSpaceGuid.BootScriptThunkDataPtr|0x0|UINT64|= 0x30000001 --=20 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel From nobody Mon Apr 29 08:09:50 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1488856484602712.937066536162; Mon, 6 Mar 2017 19:14:44 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 43EF580356; Mon, 6 Mar 2017 19:14:39 -0800 (PST) Received: from mail-qk0-x243.google.com (mail-qk0-x243.google.com [IPv6:2607:f8b0:400d:c09::243]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7FC458034B for ; Mon, 6 Mar 2017 19:14:37 -0800 (PST) Received: by mail-qk0-x243.google.com with SMTP id j127so31381423qke.0 for ; Mon, 06 Mar 2017 19:14:37 -0800 (PST) Received: from foober.ini.cmu.edu (pool-108-39-248-175.pitbpa.fios.verizon.net. [108.39.248.175]) by smtp.gmail.com with ESMTPSA id v26sm2901013qtc.13.2017.03.06.19.14.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 19:14:35 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=n5LFwM9HgxoBAMJcO5XE9ZGs7dIOF8m7Ez9x1PyrHz4=; b=YzaEYclI+wLdIFbVCAzylsvw7JXTEr3qdgEqDAwin6ba6ygv4Y8sfYLJEXqeVPD1cr U243vuQxmKs9Sn6wbOLTeutUTh11e368z4RbifdkdpcJproALXTbqXnbSe3PYM9PzTXu sQxDUA4pkWa+oCIw9Li/5t/s843ygg3RwLup3BdSw5Fucxr9KSadlewZtjVgYOgLr39f z34BahCyZLXCpaEoywSK4Ulbg77Yx82w+bRjCqj8qhQmLS289Cr/jCjm8lF/8p5sM8rs pvlATd93SaMK/9OO6puyp0HpGypzCzfGamcDSgnEAg2Qug1B5yTo1CSqxuWGV/p8OVEX 2DnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=n5LFwM9HgxoBAMJcO5XE9ZGs7dIOF8m7Ez9x1PyrHz4=; b=mieALnYzqfOmxHfHyvPIlX1ZV7sNLM3TAduPQedHF2ZUwgg1lD3U5IB8zBk/FVWFcX NoxYl7Lo3bqqAs2XWG4x5OaEv88bInYiMORC/QQFHK96KK55Do/cn5U3pIdEqUe/3dto QuRlaJNm2GRQ5OdlppOoOFczMAngcY80LrdFxrMv4g0OUS+wCz2FkVH+tbvgtYXJLLGw 9ax31OGu38MUWoZzs0Ri7rcBSC6lawIDxoV4UgY4Wee5Fq3ris1VPq1gBiMHdfcHC3R1 kFxAO+Vl7DVu8Xgp/1t2qMNhVuYnFtEbhB21Q7WKSTgePvv5h8LVeVW8EnbmKrjdWFla 5njQ== X-Gm-Message-State: AMke39leNVdwok00Tgvq1Z4EFm9+Rzglyna5Ki3ouloP/9QD26pjQZRyK6IfIahJACSPsg== X-Received: by 10.55.169.135 with SMTP id s129mr13188532qke.91.1488856476325; Mon, 06 Mar 2017 19:14:36 -0800 (PST) From: "Gabriel L. Somlo" To: edk2-devel@ml01.01.org Date: Mon, 6 Mar 2017 22:14:24 -0500 Message-Id: <1488856465-8965-6-git-send-email-gsomlo@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> References: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> Subject: [edk2] [RFC PATCH 5/6] OvmfPkg: add Apple boot support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jordan.l.justen@intel.com, lersek@redhat.com, agraf@suse.de MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Apple's boot.efi checks if the ConsoleControl protocol returns EFI_SUCCESS in both GetMode and SetMode. Apple uses a kernel extension to make parts of the DataHub protocol available to the xnu kernel. The xnu kernel then checks for FSB frequency and if it's not found fails with: "tsc_init: EFI not supported!" https://github.com/opensource-apple/xnu/blob/10.9/osfmk/i386/tsc.c Also, some firmware settings are added to AppleSupport and written to nvram. Lastly, use (already present) HFS+ filesystem driver to locate, load, and launch the Apple-provided OS X bootloader. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Reza Jelveh Signed-off-by: Gabriel Somlo --- OvmfPkg/Include/Library/AppleSupportLib.h | 28 ++++ OvmfPkg/Library/AppleSupportLib/AppleSupport.c | 107 +++++++++++++++ .../Library/AppleSupportLib/AppleSupportLib.inf | 50 +++++++ OvmfPkg/Library/AppleSupportLib/Bds.c | 151 +++++++++++++++++= ++++ OvmfPkg/Library/AppleSupportLib/Bds.h | 21 +++ OvmfPkg/Library/AppleSupportLib/Common.h | 24 ++++ OvmfPkg/Library/AppleSupportLib/Console.c | 86 ++++++++++++ OvmfPkg/Library/AppleSupportLib/Console.h | 28 ++++ OvmfPkg/Library/AppleSupportLib/Datahub.c | 104 ++++++++++++++ OvmfPkg/Library/AppleSupportLib/Datahub.h | 32 +++++ 10 files changed, 631 insertions(+) create mode 100644 OvmfPkg/Include/Library/AppleSupportLib.h create mode 100644 OvmfPkg/Library/AppleSupportLib/AppleSupport.c create mode 100644 OvmfPkg/Library/AppleSupportLib/AppleSupportLib.inf create mode 100644 OvmfPkg/Library/AppleSupportLib/Bds.c create mode 100644 OvmfPkg/Library/AppleSupportLib/Bds.h create mode 100644 OvmfPkg/Library/AppleSupportLib/Common.h create mode 100644 OvmfPkg/Library/AppleSupportLib/Console.c create mode 100644 OvmfPkg/Library/AppleSupportLib/Console.h create mode 100644 OvmfPkg/Library/AppleSupportLib/Datahub.c create mode 100644 OvmfPkg/Library/AppleSupportLib/Datahub.h diff --git a/OvmfPkg/Include/Library/AppleSupportLib.h b/OvmfPkg/Include/Li= brary/AppleSupportLib.h new file mode 100644 index 0000000..583d06b --- /dev/null +++ b/OvmfPkg/Include/Library/AppleSupportLib.h @@ -0,0 +1,28 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#ifndef _APPLESUPPORT_LIB_INCLUDED_ +#define _APPLESUPPORT_LIB_INCLUDED_ + +EFI_STATUS +EFIAPI +InitializeAppleSupport ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +BdsBootApple (); + +#endif diff --git a/OvmfPkg/Library/AppleSupportLib/AppleSupport.c b/OvmfPkg/Libra= ry/AppleSupportLib/AppleSupport.c new file mode 100644 index 0000000..92f7d79 --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/AppleSupport.c @@ -0,0 +1,107 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#include "Console.h" +#include "Datahub.h" + +#include +#include +#include +#include +#include +#include +#include + + +EFI_GUID gAppleFirmwareVariableGuid =3D { + 0x4D1EDE05, 0x38C7, 0x4A6A, {0x9C, 0xC6, 0x4B, 0xCC, 0xA8, 0xB3, 0x8C,= 0x14 } +}; + +/** + Register Handler for the specified interrupt source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param Handler Callback for interrupt. NULL to unregister + + @retval EFI_SUCCESS The firmware has successfully stored the= variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits= was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold = the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved due to a= hardware failure. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be delet= ed. + @retval EFI_SECURITY_VIOLATION The variable could not be written due to= EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set but the AuthInfo does NOT pass the validation check carried + out by the firmware. + +**/ +EFI_STATUS +InitializeFirmware () +{ + EFI_STATUS Status; + + UINT32 BackgroundClear =3D 0x00000000; + UINT32 FwFeatures =3D 0x80000015; + UINT32 FwFeaturesMask =3D 0x800003ff; + + Status =3D gRT->SetVariable(L"BackgroundClear", + &gAppleFirmwareVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTS= ERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(BackgroundClear), &BackgroundClear); + + Status =3D gRT->SetVariable(L"FirmwareFeatures", + &gAppleFirmwareVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTS= ERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(FwFeatures), &FwFeatures); + + Status =3D gRT->SetVariable(L"FirmwareFeaturesMask", + &gAppleFirmwareVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTS= ERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(FwFeaturesMask), &FwFeaturesMask); + + return Status; +} + +/** + Register driver. + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Driver registered + +**/ +EFI_STATUS +EFIAPI +InitializeAppleSupport ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status =3D InitializeConsoleControl(ImageHandle); + ASSERT_EFI_ERROR (Status); + + Status =3D InitializeDatahub(ImageHandle); + ASSERT_EFI_ERROR(Status); + + Status =3D InitializeFirmware(); + ASSERT_EFI_ERROR(Status); + + return Status; +} diff --git a/OvmfPkg/Library/AppleSupportLib/AppleSupportLib.inf b/OvmfPkg/= Library/AppleSupportLib/AppleSupportLib.inf new file mode 100644 index 0000000..6caf29d --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/AppleSupportLib.inf @@ -0,0 +1,50 @@ +#/* @file +# Copyright (c) 2014, Reza Jelveh. All rights reserved. +# +# This program and the accompanying materials # are licensed and made +# available under the terms and conditions of the BSD License which +# accompanies this distribution. The full text of the license may be +# found at http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +# +#*/ + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D AppleSupportLib + FILE_GUID =3D CEC880AF-68DF-4CDF-BBA5-FF9B202382AB + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D AppleSupportLib + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + AppleSupport.c + Console.c + Datahub.c + Bds.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + EdkCompatibilityPkg/EdkCompatibilityPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + BaseLib + DebugLib + MemoryAllocationLib + BaseMemoryLib + +[Protocols] + gEfiConsoleControlProtocolGuid + gEfiDataHubProtocolGuid diff --git a/OvmfPkg/Library/AppleSupportLib/Bds.c b/OvmfPkg/Library/AppleS= upportLib/Bds.c new file mode 100644 index 0000000..88f7437 --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Bds.c @@ -0,0 +1,151 @@ +#include "Common.h" +#include "Bds.h" + +#include + +#include +#include +#include +#include + +#include + +EFI_STATUS +BdsFileSystemLoadImage ( + IN EFI_HANDLE Handle, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *ImageSize + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; + EFI_FILE_PROTOCOL *Fs; + EFI_FILE_INFO *FileInfo; + EFI_FILE_PROTOCOL *File; + UINTN Size; + + /* FilePathDevicePath =3D (FILEPATH_DEVICE_PATH*)RemainingDevicePath; */ + + Status =3D gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGui= d, (VOID **)&FsProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + // Try to Open the volume and get root directory + Status =3D FsProtocol->OpenVolume (FsProtocol, &Fs); + if (EFI_ERROR (Status)) { + return Status; + } + + File =3D NULL; + Status =3D Fs->Open (Fs, &File, EFI_CORESERVICES, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + return Status; + } + + Size =3D 0; + File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL); + FileInfo =3D AllocatePool (Size); + Status =3D File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the file size + Size =3D FileInfo->FileSize; + if (ImageSize) { + *ImageSize =3D Size; + } + FreePool (FileInfo); + + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PA= GES(Size), Image); + // Try to allocate in any pages if failed to allocate memory at the defi= ned location + if ((Status =3D=3D EFI_OUT_OF_RESOURCES) && (Type !=3D AllocateAnyPages)= ) { + Status =3D gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, = EFI_SIZE_TO_PAGES(Size), Image); + } + if (!EFI_ERROR (Status)) { + Status =3D File->Read (File, &Size, (VOID*)(UINTN)(*Image)); + } + + return Status; +} + + +/** + Start an EFI Application from a Device Path + + @param ParentImageHandle Handle of the calling image + @param DevicePath Location of the EFI Application + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been = found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to sto= re the matching results. + +**/ +EFI_STATUS +BdsStartEfiApplication ( + IN EFI_HANDLE Handle, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE ImageHandle; + EFI_PHYSICAL_ADDRESS BinaryBuffer; + UINTN BinarySize; + + // Find the nearest supported file loader + Status =3D BdsFileSystemLoadImage (Handle, AllocateAnyPages, &BinaryBuff= er, &BinarySize); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_INFO, "=3D=3D Bds could not load System image =3D=3D")); + return Status; + } + + // Load the image from the Buffer with Boot Services function + Status =3D gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(= UINTN)BinaryBuffer, BinarySize, &ImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // Before calling the image, enable the Watchdog Timer for the 5 Minute= period + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + // Start the image + Status =3D gBS->StartImage (ImageHandle, NULL, NULL); + // Clear the Watchdog Timer after the image returns + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + + return Status; +} + + +EFI_STATUS +BdsBootApple () +{ + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_HANDLE *SimpleFileSystemHandles; + UINTN NumberSimpleFileSystemHandles; + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumberSimpleFileSystemHandles, + &SimpleFileSystemHandles + ); + DEBUG((EFI_D_INFO, "Number Device File System: %d\n", NumberSimpleFileSy= stemHandles)); + for (Index =3D 0; Index < NumberSimpleFileSystemHandles; Index++) { + // + // Get the device path size of SimpleFileSystem handle + // + TempDevicePath =3D DevicePathFromHandle (SimpleFileSystemHandles[Index= ]); + BdsStartEfiApplication ( + SimpleFileSystemHandles[Index], + gImageHandle, + TempDevicePath + ); + + } + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Library/AppleSupportLib/Bds.h b/OvmfPkg/Library/AppleS= upportLib/Bds.h new file mode 100644 index 0000000..725d03b --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Bds.h @@ -0,0 +1,21 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + + +#ifndef _APPLESUPPORT_BDS_H_INCLUDED_ +#define _APPLESUPPORT_BDS_H_INCLUDED_ + +#define EFI_CORESERVICES L"System\\Library\\CoreServices\\boot.efi" + +#endif diff --git a/OvmfPkg/Library/AppleSupportLib/Common.h b/OvmfPkg/Library/App= leSupportLib/Common.h new file mode 100644 index 0000000..725f2af --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Common.h @@ -0,0 +1,24 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + + +#ifndef _APPLESUPPORT_COMMON_H_INCLUDED_ +#define _APPLESUPPORT_COMMON_H_INCLUDED_ + +#include +#include +#include +#include + +#endif diff --git a/OvmfPkg/Library/AppleSupportLib/Console.c b/OvmfPkg/Library/Ap= pleSupportLib/Console.c new file mode 100644 index 0000000..5f23300 --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Console.c @@ -0,0 +1,86 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#include "Console.h" + +EFI_STATUS EFIAPI +GetModeImpl( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *GopUgaExists, OPTIONAL + OUT BOOLEAN *StdInLocked OPTIONAL + ) +{ + *Mode =3D EfiConsoleControlScreenGraphics; + + if (GopUgaExists) + *GopUgaExists =3D TRUE; + if (StdInLocked) + *StdInLocked =3D FALSE; + return EFI_SUCCESS; +} + +EFI_STATUS EFIAPI +SetModeImpl( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS EFIAPI +LockStdInImpl( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +{ + return EFI_SUCCESS; +} + + + +EFI_CONSOLE_CONTROL_PROTOCOL gConsoleController =3D +{ + GetModeImpl, + SetModeImpl, +}; + +/** + Install ConsoleControl protocol, which is needed for Apple's + boot.efi + + @param ImageHandle of the loaded driver + + @retval EFI_SUCCESS Successfully installed protocol handler + @retval EFI_DEVICE_ERROR ConsoleProtocol could not be installed + +**/ +EFI_STATUS +EFIAPI +InitializeConsoleControl ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiConsoleControlProtocolGuid, + &gConsoleController, + NULL + ); + + return Status; +} diff --git a/OvmfPkg/Library/AppleSupportLib/Console.h b/OvmfPkg/Library/Ap= pleSupportLib/Console.h new file mode 100644 index 0000000..dabf902 --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Console.h @@ -0,0 +1,28 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#ifndef _APPLESUPPORT_CONSOLE_H_INCLUDED_ +#define _APPLESUPPORT_CONSOLE_H_INCLUDED_ + +#include "Common.h" + +#include + +EFI_STATUS +EFIAPI +InitializeConsoleControl ( + IN EFI_HANDLE ImageHandle + ); + +#endif diff --git a/OvmfPkg/Library/AppleSupportLib/Datahub.c b/OvmfPkg/Library/Ap= pleSupportLib/Datahub.c new file mode 100644 index 0000000..3f1ec56 --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Datahub.c @@ -0,0 +1,104 @@ +/** @file +* +* Copyright (c) 2011, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#include "Datahub.h" + +EFI_GUID gAppleSystemInfoProducerNameGuid =3D {0x64517CC8, 0x6561, 0x4051,= {0xB0, 0x3C, 0x59, 0x64, 0xB6, 0x0F, 0x4C, 0x7A}}; +EFI_GUID gAppleFsbFrequencyPropertyGuid =3D {0xD1A04D55, 0x75B9, 0x41A3, {= 0x90, 0x36, 0x8F, 0x4A, 0x26, 0x1C, 0xBB, 0xA2}}; +EFI_GUID gAppleDevicePathsSupportedGuid =3D {0x5BB91CF7, 0xD816, 0x404B, {= 0x86, 0x72, 0x68, 0xF2, 0x7F, 0x78, 0x31, 0xDC}}; + +typedef struct { + UINT32 DataNameSize; + UINT32 DataSize; +} EFI_PROPERTY_SUBCLASS_RECORD; + +typedef struct { + EFI_SUBCLASS_TYPE1_HEADER Header; + EFI_PROPERTY_SUBCLASS_RECORD Record; +} EFI_PROPERTY_SUBCLASS_DATA; + + +EFI_STATUS +SetEfiPlatformProperty ( + IN EFI_DATA_HUB_PROTOCOL *DataHub, + IN CONST EFI_STRING Name, + EFI_GUID EfiPropertyGuid, + VOID *Data, + UINT32 DataSize + ) +{ + EFI_STATUS Status; + UINT32 DataNameSize; + EFI_PROPERTY_SUBCLASS_DATA *DataRecord; + + DataNameSize =3D (UINT32)StrSize(Name); + + DataRecord =3D AllocateZeroPool (sizeof (EFI_PROPERTY_SUBCLASS_DATA) + D= ataNameSize + DataSize); + ASSERT (DataRecord !=3D NULL); + + DataRecord->Header.Version =3D EFI_DATA_RECORD_HEADER_VERSION; + DataRecord->Header.HeaderSize =3D sizeof(EFI_SUBCLASS_TYPE1_HEADER); + DataRecord->Header.Instance =3D 0xFFFF; + DataRecord->Header.SubInstance =3D 0xFFFF; + DataRecord->Header.RecordType =3D 0xFFFFFFFF; + DataRecord->Record.DataNameSize =3D DataNameSize; + DataRecord->Record.DataSize =3D DataSize; + + + CopyMem((UINT8 *)DataRecord + sizeof(EFI_PROPERTY_SUBCLASS_DATA), Name, = DataNameSize); + CopyMem((UINT8 *)DataRecord + sizeof(EFI_PROPERTY_SUBCLASS_DATA) + DataN= ameSize, Data, DataSize); + + Status =3D DataHub->LogData(DataHub, &EfiPropertyGuid, &gAppleSystemInfo= ProducerNameGuid, + EFI_DATA_RECORD_CLASS_DATA, + DataRecord, + sizeof(EFI_PROPERTY_SUBCLASS_DATA) + DataName= Size + DataSize); + + if (DataRecord) { + gBS->FreePool(DataRecord); + } + + return Status; +} + +/** + Initialize the DataHub protocols data for the xnu kernel to + detect an EFI boot. + + @param ImageHandle of the loaded driver + + @retval EFI_SUCCESS Source was updated to support Handler. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +EFI_STATUS +EFIAPI +InitializeDatahub ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_DATA_HUB_PROTOCOL *DataHub; + + Status =3D gBS->LocateProtocol(&gEfiDataHubProtocolGuid, NULL, (VOID **)= &DataHub); + ASSERT_EFI_ERROR(Status); + + UINT64 FsbFrequency =3D 667000000; + UINT32 DevicePathsSupported =3D 1; + + SetEfiPlatformProperty(DataHub, L"FSBFrequency", gAppleFsbFrequencyPrope= rtyGuid, &FsbFrequency, sizeof(UINT64)); + SetEfiPlatformProperty(DataHub, L"DevicePathsSupported", gAppleDevicePat= hsSupportedGuid, &DevicePathsSupported, sizeof(UINT32)); + ASSERT_EFI_ERROR(Status); + + return Status; +} diff --git a/OvmfPkg/Library/AppleSupportLib/Datahub.h b/OvmfPkg/Library/Ap= pleSupportLib/Datahub.h new file mode 100644 index 0000000..d7f8806 --- /dev/null +++ b/OvmfPkg/Library/AppleSupportLib/Datahub.h @@ -0,0 +1,32 @@ +/** @file +* +* Copyright (c) 2014, Reza Jelveh. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#ifndef _APPLESUPPORT_DATAHUB_H_INCLUDED_ +#define _APPLESUPPORT_DATAHUB_H_INCLUDED_ + +#include "Common.h" + +#include +#include +#include +#include +#include + +EFI_STATUS +EFIAPI +InitializeDatahub ( + IN EFI_HANDLE ImageHandle + ); + +#endif --=20 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel From nobody Mon Apr 29 08:09:50 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1488856489763997.254305708301; Mon, 6 Mar 2017 19:14:49 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id B67478035D; Mon, 6 Mar 2017 19:14:39 -0800 (PST) Received: from mail-qk0-x242.google.com (mail-qk0-x242.google.com [IPv6:2607:f8b0:400d:c09::242]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 09AEB80354 for ; Mon, 6 Mar 2017 19:14:38 -0800 (PST) Received: by mail-qk0-x242.google.com with SMTP id o135so8866786qke.2 for ; Mon, 06 Mar 2017 19:14:38 -0800 (PST) Received: from foober.ini.cmu.edu (pool-108-39-248-175.pitbpa.fios.verizon.net. [108.39.248.175]) by smtp.gmail.com with ESMTPSA id v26sm2901013qtc.13.2017.03.06.19.14.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Mar 2017 19:14:36 -0800 (PST) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=zKA4kPmDfUq6SUVG4c9znOYy3kDzgMcMHHvdi6roZws=; b=brIYKuop3GGHvU4awZCbQ2c+LeIYROPPhLwMLjT7+h+1ZEQHKiFF7dxwk95mcoshOu c71zZXvyIks5ce5znDMGSkh7jIeFQwWBjwaqt/q7uSByPiW8CCiI6AcJ4znVpx+GZjXe SqQg/G9UgwBmUVtwYmJrBVrYrBCzFOUjMM2oYe8sDAeCmSX19JTuKt9T3jZ68so2hTAA RYJt0blymgPjm83AnuwbtR++73i7126rCATJdNK2eKayb8H92MqJo/Q18liJRIFDI2lC oLmNBUbeQMXhovkg+wE/r74C3nxWv4OHXGuF8nVRpIz8x43ageZSMWQNaMwv0Qk9ocj5 +sjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=zKA4kPmDfUq6SUVG4c9znOYy3kDzgMcMHHvdi6roZws=; b=NbTMrK7JIBbblLU2br/Ql0IXoImqHmKIfae15UoB5fnDWeiN61Z8MSFdXW9IYwhukO oB3peDTuZ6lRDTNulLQ+cEvVNIGofGf6MnekX0CASDPvQmOrtIAoUW8cr6VqgbAv+3lS mPcfWi5wKveKE3g26LUo0S3Ur/R54QdPIFybtM1szFgapucPv1ozc9AOiOTsuM76Egmx N6bY4mycWECi7hZzL0Fss/Q4L25V8WankYBMe97cUGkaqBj4tWXkD/lvnswovZ3umkSv TiuUm1mu3Lci9NwfdQuOYaJmKkrR1fg+fapy3POQrRyGLqHSyW7p+79Cpmy5QwQ4elDx 2FQw== X-Gm-Message-State: AMke39kdCU1gj8GkNI3yrAnxUDRu+Au9XtVFlF0+NtLKJprTtm5KQuH4gfDKr3qGW2Jiow== X-Received: by 10.233.232.21 with SMTP id a21mr19877947qkg.180.1488856477063; Mon, 06 Mar 2017 19:14:37 -0800 (PST) From: "Gabriel L. Somlo" To: edk2-devel@ml01.01.org Date: Mon, 6 Mar 2017 22:14:25 -0500 Message-Id: <1488856465-8965-7-git-send-email-gsomlo@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> References: <1488856465-8965-1-git-send-email-gsomlo@gmail.com> Subject: [edk2] [RFC PATCH 6/6] OvmfPkg: enable AppleSupport library for Ovmf firmware X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jordan.l.justen@intel.com, lersek@redhat.com, agraf@suse.de MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Reza Jelveh Signed-off-by: Gabriel Somlo --- OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c | 10 ++++++= ++++ OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h | 1 + .../Library/PlatformBootManagerLib/PlatformBootManagerLib.inf | 1 + OvmfPkg/OvmfPkgIa32.dsc | 8 ++++++= ++ OvmfPkg/OvmfPkgIa32.fdf | 3 +++ OvmfPkg/OvmfPkgIa32X64.dsc | 8 ++++++= ++ OvmfPkg/OvmfPkgIa32X64.fdf | 3 +++ OvmfPkg/OvmfPkgX64.dsc | 8 ++++++= ++ OvmfPkg/OvmfPkgX64.fdf | 3 +++ 9 files changed, 45 insertions(+) diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg= /Library/PlatformBootManagerLib/BdsPlatform.c index cc35630..9f6be90 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c @@ -381,6 +381,11 @@ Returns: } =20 // + // Initialize AppleSupport library + // + InitializeAppleSupport (gImageHandle, gST); + + // // Prevent further changes to LockBoxes or SMRAM. // Handle =3D NULL; @@ -1474,6 +1479,11 @@ Routine Description: =20 RemoveStaleFvFileOptions (); SetBootOrderFromQemu (); + + // + // Locate and launch Apple's OS X bootloader + // + BdsBootApple (); } =20 /** diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h b/OvmfPkg= /Library/PlatformBootManagerLib/BdsPlatform.h index ec58efa..3fa7712 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h @@ -49,6 +49,7 @@ Abstract: #include #include #include +#include =20 #include #include diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.= inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf index f9e35c9..66d31a5 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -40,6 +40,7 @@ OvmfPkg/OvmfPkg.dec =20 [LibraryClasses] + AppleSupportLib BaseLib MemoryAllocationLib UefiBootServicesTableLib diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 0bce56b..da83cba 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -176,6 +176,8 @@ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib= /BaseOrderedCollectionRedBlackTreeLib.inf XenHypercallLib|OvmfPkg/Library/XenHypercallLib/XenHypercallLib.inf =20 + AppleSupportLib|OvmfPkg/Library/AppleSupportLib/AppleSupportLib.inf + [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf =20 @@ -696,6 +698,12 @@ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsRes= ourceTableDxe.inf =20 # + # Apple Support + # + OvmfPkg/FswHfsPlus/FswHfsPlus.inf + IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + + # # Network Support # MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index 09c1658..0e00bd9 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -280,6 +280,9 @@ INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveS= tateDxe.inf INF MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorD= xe.inf INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphics= ResourceTableDxe.inf =20 +INF OvmfPkg/FswHfsPlus/FswHfsPlus.inf +INF IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + INF FatPkg/EnhancedFatDxe/Fat.inf =20 !ifndef $(USE_OLD_SHELL) diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 56f7ff9..a38dc9b 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -181,6 +181,8 @@ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib= /BaseOrderedCollectionRedBlackTreeLib.inf XenHypercallLib|OvmfPkg/Library/XenHypercallLib/XenHypercallLib.inf =20 + AppleSupportLib|OvmfPkg/Library/AppleSupportLib/AppleSupportLib.inf + [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf =20 @@ -705,6 +707,12 @@ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsRes= ourceTableDxe.inf =20 # + # Apple Support + # + OvmfPkg/FswHfsPlus/FswHfsPlus.inf + IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + + # # Network Support # MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index 5233314..2bd2d77 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -280,6 +280,9 @@ INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveS= tateDxe.inf INF MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorD= xe.inf INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphics= ResourceTableDxe.inf =20 +INF OvmfPkg/FswHfsPlus/FswHfsPlus.inf +INF IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + INF FatPkg/EnhancedFatDxe/Fat.inf =20 !ifndef $(USE_OLD_SHELL) diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index d0b0b0e..2bff68d 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -181,6 +181,8 @@ OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib= /BaseOrderedCollectionRedBlackTreeLib.inf XenHypercallLib|OvmfPkg/Library/XenHypercallLib/XenHypercallLib.inf =20 + AppleSupportLib|OvmfPkg/Library/AppleSupportLib/AppleSupportLib.inf + [LibraryClasses.common] BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf =20 @@ -703,6 +705,12 @@ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsRes= ourceTableDxe.inf =20 # + # Apple Support + # + OvmfPkg/FswHfsPlus/FswHfsPlus.inf + IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + + # # Network Support # MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf index 3615010..0165a63 100644 --- a/OvmfPkg/OvmfPkgX64.fdf +++ b/OvmfPkg/OvmfPkgX64.fdf @@ -280,6 +280,9 @@ INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveS= tateDxe.inf INF MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorD= xe.inf INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphics= ResourceTableDxe.inf =20 +INF OvmfPkg/FswHfsPlus/FswHfsPlus.inf +INF IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf + INF FatPkg/EnhancedFatDxe/Fat.inf =20 !ifndef $(USE_OLD_SHELL) --=20 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel