pax_global_header00006660000000000000000000000064150431502360014511gustar00rootroot0000000000000052 comment=c7177a6f37f3b06eacd589bd29ddbe8462127fe0 ubustub-1/000077500000000000000000000000001504315023600127045ustar00rootroot00000000000000ubustub-1/.gitignore000066400000000000000000000000301504315023600146650ustar00rootroot00000000000000*.o ubustub ubustub.efi ubustub-1/LICENSE.LGPL2.1000066400000000000000000000636421504315023600147020ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ubustub-1/Make.defaults000066400000000000000000000020441504315023600153120ustar00rootroot00000000000000CFLAGS += -I include CFLAGS += -DRELATIVE_SOURCE_PATH="\".\"" CFLAGS += -fno-strict-aliasing CFLAGS += -ffreestanding CFLAGS += -fshort-wchar CFLAGS += -fwide-exec-charset=UCS2 CFLAGS += -mstack-protector-guard=global CFLAGS += -DCOLOR_NORMAL=0x0f CFLAGS += -fno-lto CFLAGS += '-DEFI_MACHINE_TYPE_NAME="x64"' CFLAGS += '-DGIT_VERSION="1.0-ubuntu0"' CFLAGS += -O2 LDFLAGS += -nostdlib LDFLAGS += -static-pie LDFLAGS += -Wl,--entry=efi_main LDFLAGS += -Wl,--fatal-warnings LDFLAGS += -Wl,-static,-pie,--no-dynamic-linker,-z,text LDFLAGS += -z common-page-size=4096 LDFLAGS += -z max-page-size=4096 LDFLAGS += -z noexecstack LDFLAGS += -z relro LDFLAGS += -z separate-code LDFLAGS += $(shell $(CC) -print-libgcc-file-name) LDFLAGS += -Wl,-z,nopack-relative-relocs LDFLAGS += -fcf-protection=none LDFLAGS += -fno-asynchronous-unwind-tables LDFLAGS += -fno-exceptions -fno-unwind-tables LDFLAGS += -fno-lto # # DEBUG # CFLAGS += -O0 -g # # Find unused functions # CFLAGS += -ffunction-sections # LDFLAGS += -Wl,--gc-sections # LDFLAGS += -Wl,--print-gc-sections ubustub-1/Makefile000066400000000000000000000024021504315023600143420ustar00rootroot00000000000000# SPDX-License-Identifier: LGPL-2.1-or-later include ./Make.defaults ARCH?= $(shell uname -m) PREFIX?= /usr ifeq ($(ARCH),x86_64) CFLAGS += -m64 -march=x86-64 -mno-red-zone -mgeneral-regs-only -maccumulate-outgoing-args LDFLAGS += -m64 endif ifeq ($(ARCH),aarch64) CFLAGS += -mgeneral-regs-only endif OBJS = devicetree.o device-path-util.o efi-efivars.o efi-log.o \ efi-string.o export-vars.o linux.o part-discovery.o pe.o shim.o \ string-util-fundamental.o stub.o url-discovery.o util.o uki.o \ random-seed.o smbios.o secure-boot.o initrd.o efi-firmware.o chid.o \ sha256.o console.o edid.o sha1.o .PHONY: all clean install all: ubustub.efi %.o: %.c $(CC) $< $(CFLAGS) -c -o $@ ubustub.efi: ubustub ./elf2efi.py --version-major=6 --version-minor=16 \ --efi-major=1 --efi-minor=1 --subsystem=10 \ --minimum-sections=50 \ --copy-sections=".sbat,.sdmagic,.osrel" $< $@ ubustub: $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) install: ubustub.efi install -m 755 -d ${DESTDIR}${PREFIX}/lib/ubustub install -m 644 -t ${DESTDIR}${PREFIX}/lib/ubustub ubustub.efi install -m 755 -d ${DESTDIR}${PREFIX}/share/ubustub/hwids install -m 644 -t ${DESTDIR}${PREFIX}/share/ubustub/hwids hwids/json/* clean: rm -f $(OBJS) rm -f ubustub rm -f ubustub.efi ubustub-1/README.md000066400000000000000000000040151504315023600141630ustar00rootroot00000000000000# Ubustub A minimal alternative to [systemd-stub(7)](https://manpages.ubuntu.com/manpages/plucky/man7/systemd-stub.7.html) that serves a single purpose: **Automatically loading machine specific device trees embedded within the kernel image.** ubustub is compatible with [systemd-stub(7)](https://manpages.ubuntu.com/manpages/plucky/man7/systemd-stub.7.html) and [ukify(1)](https://manpages.ubuntu.com/manpages/plucky/man1/ukify.1.html). It is designed to seamlessly integrate with Ubuntu's current bootloader and boot security model. The resulting kernel image can be signed and verified and loaded by grub like any other kernel. Before loading the kernel, the stub generates [hwids](https://github.com/fwupd/fwupd/blob/main/docs/hwids.md) of the running machine derived from smbios and compares them to an embedded lookup table in the .hwids section of the kernel image. If a match is found it loads the corresponding device tree from the .dtbauto section before jumping tothe bundled kernel. ## Dependencies ``` # apt install python3-pyelftools systemd-ukify ``` ## Building Build the stub: ``` $ make ``` For a simple combined kernel+ubustub image bundling a single DTB you can run: ``` $ ukify build --linux=/boot/vmlinuz --stub=ubustub.efi --hwids=hwids/json --dtbauto=/boot/dtb --output=vmlinuz.efi ``` ## HWIDs The `.txt` files in hwids/txt have been generated with `fwupdtool hwids`. The can be converted to `.json` files by running `hwid2json.py` from the `hwids` directory. The `compatible` field of the resulting JSON files has to be filled in manually. # Acknowledgements This project is originally based on [systemd-stub](https://manpages.ubuntu.com/manpages/plucky/man7/systemd-stub.7.html) from the systemd project. The `.dtbauto` feature in systemd was contributed by [anonymix007](https://github.com/anonymix007/). It is inspired by the [dtbloader](https://github.com/TravMurav/dtbloader) project by Nikita Travkin and [DtbLoader.efi](https://github.com/aarch64-laptops/edk2/tree/dtbloader-app) from the aarch64-laptops project. ubustub-1/chid.c000066400000000000000000000267571504315023600140000ustar00rootroot00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ /* * Based on Nikita Travkin's dtbloader implementation. * Copyright (c) 2024 Nikita Travkin * * https://github.com/TravMurav/dtbloader/blob/main/src/chid.c */ /* * Based on Linaro dtbloader implementation. * Copyright (c) 2019, Linaro. All rights reserved. * * https://github.com/aarch64-laptops/edk2/blob/dtbloader-app/EmbeddedPkg/Application/ConfigTableLoader/CHID.c */ #include "chid.h" #include "edid.h" #include "efi-log.h" #include "efi-string.h" #include "smbios.h" #include "util.h" #include "macro-fundamental.h" #include "memory-util-fundamental.h" #include "sha1.h" static void get_chid( const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], uint32_t mask, EFI_GUID *ret_chid) { assert(mask != 0); assert(ret_chid); struct sha1_ctx ctx = {}; sha1_init_ctx(&ctx); static const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */ sha1_process_bytes(&namespace, sizeof(namespace), &ctx); for (ChidSmbiosFields i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) { if (!FLAGS_SET(mask, UINT32_C(1) << i)) continue; if (!smbios_fields[i]) { /* If some SMBIOS field is missing, don't generate the CHID, as per spec */ memzero(ret_chid, sizeof(EFI_GUID)); return; } if (i > 0) sha1_process_bytes(L"&", 2, &ctx); sha1_process_bytes(smbios_fields[i], strlen16(smbios_fields[i]) * sizeof(char16_t), &ctx); } uint8_t hash[SHA1_DIGEST_SIZE]; sha1_finish_ctx(&ctx, hash); assert_cc(sizeof(hash) >= sizeof(*ret_chid)); memcpy(ret_chid, hash, sizeof(*ret_chid)); /* Convert the resulting CHID back to little-endian: */ ret_chid->Data1 = bswap_32(ret_chid->Data1); ret_chid->Data2 = bswap_16(ret_chid->Data2); ret_chid->Data3 = bswap_16(ret_chid->Data3); /* set specific bits according to RFC4122 Section 4.1.3 */ ret_chid->Data3 = (ret_chid->Data3 & 0x0fff) | (5 << 12); ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80); } const uint32_t chid_smbios_table[CHID_TYPES_MAX] = { [0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) | (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) | (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) | (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) | (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR), [1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) | (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) | (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) | (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR), [2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) | (UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) | (UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) | (UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR), [3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT), [4] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU), [5] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME), [6] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT), [7] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU), [8] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT), [9] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME), [10] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT), [11] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY), [12] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_ENCLOSURE_TYPE), [13] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT), [14] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER), /* Extra non-standard CHIDs */ [EXTRA_CHID_BASE + 0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME)| (UINT32_C(1) << CHID_EDID_PANEL), [EXTRA_CHID_BASE + 1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_FAMILY) | (UINT32_C(1) << CHID_EDID_PANEL), [EXTRA_CHID_BASE + 2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) | (UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) | (UINT32_C(1) << CHID_EDID_PANEL), }; void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]) { assert(smbios_fields); assert(ret_chids); for (size_t i = 0; i < CHID_TYPES_MAX; i++) { if (chid_smbios_table[i] == 0) { memzero(&ret_chids[i], sizeof(EFI_GUID)); continue; } get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]); } } /* Validate the descriptor macros a bit that they match our expectations */ assert_cc(DEVICE_DESCRIPTOR_DEVICETREE == UINT32_C(0x1000001C)); assert_cc(DEVICE_DESCRIPTOR_UEFI_FW == UINT32_C(0x2000001C)); assert_cc(DEVICE_SIZE_FROM_DESCRIPTOR(DEVICE_DESCRIPTOR_DEVICETREE) == sizeof(Device)); assert_cc(DEVICE_TYPE_FROM_DESCRIPTOR(DEVICE_DESCRIPTOR_DEVICETREE) == DEVICE_TYPE_DEVICETREE); assert_cc(DEVICE_SIZE_FROM_DESCRIPTOR(DEVICE_DESCRIPTOR_UEFI_FW) == sizeof(Device)); assert_cc(DEVICE_TYPE_FROM_DESCRIPTOR(DEVICE_DESCRIPTOR_UEFI_FW) == DEVICE_TYPE_UEFI_FW); /** * smbios_to_hashable_string() - Convert ascii smbios string to stripped char16_t. */ static char16_t *smbios_to_hashable_string(const char *str) { if (!str) /* User of this function is expected to free the result. */ return xnew0(char16_t, 1); /* * We need to strip leading and trailing spaces, leading zeroes. * See fwupd/libfwupdplugin/fu-hwids-smbios.c */ while (*str == ' ') str++; while (*str == '0') str++; size_t len = strlen8(str); while (len > 0 && str[len - 1] == ' ') len--; return xstrn8_to_16(str, len); } /* This has to be in a struct due to _cleanup_ in populate_board_chids */ typedef struct SmbiosInfo { char16_t *smbios_fields[_CHID_SMBIOS_FIELDS_MAX]; } SmbiosInfo; static void smbios_info_populate(SmbiosInfo *ret_info) { assert(ret_info); RawSmbiosInfo raw; smbios_raw_info_get_cached(&raw); ret_info->smbios_fields[CHID_SMBIOS_MANUFACTURER] = smbios_to_hashable_string(raw.manufacturer); ret_info->smbios_fields[CHID_SMBIOS_PRODUCT_NAME] = smbios_to_hashable_string(raw.product_name); ret_info->smbios_fields[CHID_SMBIOS_PRODUCT_SKU] = smbios_to_hashable_string(raw.product_sku); ret_info->smbios_fields[CHID_SMBIOS_FAMILY] = smbios_to_hashable_string(raw.family); ret_info->smbios_fields[CHID_SMBIOS_BASEBOARD_PRODUCT] = smbios_to_hashable_string(raw.baseboard_product); ret_info->smbios_fields[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = smbios_to_hashable_string(raw.baseboard_manufacturer); edid_get_discovered_panel_id(&ret_info->smbios_fields[CHID_EDID_PANEL]); } static void smbios_info_done(SmbiosInfo *info) { FOREACH_ELEMENT(i, info->smbios_fields) free(*i); } static EFI_STATUS populate_board_chids(EFI_GUID ret_chids[static CHID_TYPES_MAX]) { _cleanup_(smbios_info_done) SmbiosInfo info = {}; if (!ret_chids) return EFI_INVALID_PARAMETER; smbios_info_populate(&info); chid_calculate((const char16_t *const *) info.smbios_fields, ret_chids); return EFI_SUCCESS; } EFI_STATUS chid_match(const void *hwid_buffer, size_t hwid_length, uint32_t match_type, const Device **ret_device) { EFI_STATUS status; if ((uintptr_t) hwid_buffer % alignof(Device) != 0) return EFI_INVALID_PARAMETER; const Device *devices = ASSERT_PTR(hwid_buffer); EFI_GUID chids[CHID_TYPES_MAX] = {}; static const size_t priority[] = { 17, 16, 15, 3, 6, 8, 10, 4, 5, 7, 9, 11 }; /* From most to least specific. */ status = populate_board_chids(chids); if (EFI_STATUS_IS_ERROR(status)) return log_error_status(status, "Failed to populate board CHIDs: %m"); size_t n_devices = 0; /* Count devices and check validity */ for (; (n_devices + 1) * sizeof(*devices) < hwid_length;) { if (devices[n_devices].descriptor == DEVICE_DESCRIPTOR_EOL) break; if (!IN_SET(DEVICE_TYPE_FROM_DESCRIPTOR(devices[n_devices].descriptor), DEVICE_TYPE_UEFI_FW, DEVICE_TYPE_DEVICETREE)) return EFI_UNSUPPORTED; n_devices++; } if (n_devices == 0) return EFI_NOT_FOUND; FOREACH_ELEMENT(i, priority) FOREACH_ARRAY(dev, devices, n_devices) { /* Can't take a pointer to a packed struct member, so copy to a local variable */ EFI_GUID chid = dev->chid; if (DEVICE_TYPE_FROM_DESCRIPTOR(dev->descriptor) != match_type) continue; if (efi_guid_equal(&chids[*i], &chid)) { *ret_device = dev; return EFI_SUCCESS; } } return EFI_NOT_FOUND; } ubustub-1/console.c000066400000000000000000000340261504315023600145170ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "console.h" #include "efi-log.h" #include "proto/graphics-output.h" #define SYSTEM_FONT_WIDTH 8 #define SYSTEM_FONT_HEIGHT 19 #define HORIZONTAL_MAX_OK 1920 #define VERTICAL_MAX_OK 1080 #define VIEWPORT_RATIO 10 static void event_closep(EFI_EVENT *event) { if (!*event) return; BS->CloseEvent(*event); } /* * Reading input from the console sounds like an easy task to do, but thanks to broken * firmware it is actually a nightmare. * * There is a SimpleTextInput and SimpleTextInputEx API for this. Ideally we want to use * TextInputEx, because that gives us Ctrl/Alt/Shift key state information. Unfortunately, * it is not always available and sometimes just non-functional. * * On some firmware, calling ReadKeyStroke or ReadKeyStrokeEx on the default console input * device will just freeze no matter what (even though it *reported* being ready). * Also, multiple input protocols can be backed by the same device, but they can be out of * sync. Falling back on a different protocol can end up with double input. * * Therefore, we will preferably use TextInputEx for ConIn if that is available. Additionally, * we look for the first TextInputEx device the firmware gives us as a fallback option. It * will replace ConInEx permanently if it ever reports a key press. * Lastly, a timer event allows us to provide a input timeout without having to call into * any input functions that can freeze on us or using a busy/stall loop. */ EFI_STATUS console_key_read(uint64_t *ret_key, uint64_t timeout_usec) { static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conInEx = NULL, *extraInEx = NULL; static bool checked = false; size_t index; EFI_STATUS err; _cleanup_(event_closep) EFI_EVENT timer = NULL; if (!checked) { /* Get the *first* TextInputEx device. */ err = BS->LocateProtocol( MAKE_GUID_PTR(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL), NULL, (void **) &extraInEx); if (err != EFI_SUCCESS || BS->CheckEvent(extraInEx->WaitForKeyEx) == EFI_INVALID_PARAMETER) /* If WaitForKeyEx fails here, the firmware pretends it talks this * protocol, but it really doesn't. */ extraInEx = NULL; /* Get the TextInputEx version of ST->ConIn. */ err = BS->HandleProtocol( ST->ConsoleInHandle, MAKE_GUID_PTR(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL), (void **) &conInEx); if (err != EFI_SUCCESS || BS->CheckEvent(conInEx->WaitForKeyEx) == EFI_INVALID_PARAMETER) conInEx = NULL; if (conInEx == extraInEx) extraInEx = NULL; checked = true; } err = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer); if (err != EFI_SUCCESS) return log_error_status(err, "Error creating timer event: %m"); EFI_EVENT events[] = { timer, conInEx ? conInEx->WaitForKeyEx : ST->ConIn->WaitForKey, extraInEx ? extraInEx->WaitForKeyEx : NULL, }; size_t n_events = extraInEx ? 3 : 2; /* Watchdog rearming loop in case the user never provides us with input or some * broken firmware never returns from WaitForEvent. */ for (;;) { uint64_t watchdog_timeout_sec = 5 * 60, watchdog_ping_usec = watchdog_timeout_sec / 2 * 1000 * 1000; /* SetTimer expects 100ns units for some reason. */ err = BS->SetTimer( timer, TimerRelative, MIN(timeout_usec, watchdog_ping_usec) * 10); if (err != EFI_SUCCESS) return log_error_status(err, "Error arming timer event: %m"); (void) BS->SetWatchdogTimer(watchdog_timeout_sec, 0x10000, 0, NULL); err = BS->WaitForEvent(n_events, events, &index); (void) BS->SetWatchdogTimer(watchdog_timeout_sec, 0x10000, 0, NULL); if (err != EFI_SUCCESS) return log_error_status(err, "Error waiting for events: %m"); /* We have keyboard input, process it after this loop. */ if (timer != events[index]) break; /* The EFI timer fired instead. If this was a watchdog timeout, loop again. */ if (timeout_usec == UINT64_MAX) continue; else if (timeout_usec > watchdog_ping_usec) { timeout_usec -= watchdog_ping_usec; continue; } /* The caller requested a timeout? They shall have one! */ return EFI_TIMEOUT; } /* If the extra input device we found returns something, always use that instead * to work around broken firmware freezing on ConIn/ConInEx. */ if (extraInEx && BS->CheckEvent(extraInEx->WaitForKeyEx) == EFI_SUCCESS) conInEx = TAKE_PTR(extraInEx); /* Do not fall back to ConIn if we have a ConIn that supports TextInputEx. * The two may be out of sync on some firmware, giving us double input. */ if (conInEx) { EFI_KEY_DATA keydata; uint32_t shift = 0; err = conInEx->ReadKeyStrokeEx(conInEx, &keydata); if (err != EFI_SUCCESS) return err; if (FLAGS_SET(keydata.KeyState.KeyShiftState, EFI_SHIFT_STATE_VALID)) { /* Do not distinguish between left and right keys (set both flags). */ if (keydata.KeyState.KeyShiftState & EFI_CONTROL_PRESSED) shift |= EFI_CONTROL_PRESSED; if (keydata.KeyState.KeyShiftState & EFI_ALT_PRESSED) shift |= EFI_ALT_PRESSED; if (keydata.KeyState.KeyShiftState & EFI_LOGO_PRESSED) shift |= EFI_LOGO_PRESSED; /* Shift is not supposed to be reported for keys that can be represented as uppercase * unicode chars (Shift+f is reported as F instead). Some firmware does it anyway, so * filter those out. */ if ((keydata.KeyState.KeyShiftState & EFI_SHIFT_PRESSED) && keydata.Key.UnicodeChar == 0) shift |= EFI_SHIFT_PRESSED; } /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */ if (ret_key) *ret_key = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar); return EFI_SUCCESS; } else if (BS->CheckEvent(ST->ConIn->WaitForKey) == EFI_SUCCESS) { EFI_INPUT_KEY k; err = ST->ConIn->ReadKeyStroke(ST->ConIn, &k); if (err != EFI_SUCCESS) return err; if (ret_key) *ret_key = KEYPRESS(0, k.ScanCode, k.UnicodeChar); return EFI_SUCCESS; } return EFI_NOT_READY; } static EFI_STATUS change_mode(int64_t mode) { EFI_STATUS err; int32_t old_mode; /* SetMode expects a size_t, so make sure these values are sane. */ mode = CLAMP(mode, CONSOLE_MODE_RANGE_MIN, CONSOLE_MODE_RANGE_MAX); old_mode = MAX(CONSOLE_MODE_RANGE_MIN, ST->ConOut->Mode->Mode); log_wait(); err = ST->ConOut->SetMode(ST->ConOut, mode); if (err == EFI_SUCCESS) return EFI_SUCCESS; /* Something went wrong. Output is probably borked, so try to revert to previous mode. */ if (ST->ConOut->SetMode(ST->ConOut, old_mode) == EFI_SUCCESS) return err; /* Maybe the device is on fire? */ ST->ConOut->Reset(ST->ConOut, true); ST->ConOut->SetMode(ST->ConOut, CONSOLE_MODE_RANGE_MIN); return err; } EFI_STATUS query_screen_resolution(uint32_t *ret_w, uint32_t *ret_h) { EFI_STATUS err; EFI_GRAPHICS_OUTPUT_PROTOCOL *go; err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_GRAPHICS_OUTPUT_PROTOCOL), NULL, (void **) &go); if (err != EFI_SUCCESS) return err; if (!go->Mode || !go->Mode->Info) return EFI_DEVICE_ERROR; *ret_w = go->Mode->Info->HorizontalResolution; *ret_h = go->Mode->Info->VerticalResolution; return EFI_SUCCESS; } static int64_t get_auto_mode(void) { uint32_t screen_width, screen_height; if (query_screen_resolution(&screen_width, &screen_height) == EFI_SUCCESS) { bool keep = false; /* Start verifying if we are in a resolution larger than Full HD * (1920x1080). If we're not, assume we're in a good mode and do not * try to change it. */ if (screen_width <= HORIZONTAL_MAX_OK && screen_height <= VERTICAL_MAX_OK) keep = true; /* For larger resolutions, calculate the ratio of the total screen * area to the text viewport area. If it's less than 10 times bigger, * then assume the text is readable and keep the text mode. */ else { uint64_t text_area; size_t x_max, y_max; uint64_t screen_area = (uint64_t)screen_width * (uint64_t)screen_height; console_query_mode(&x_max, &y_max); text_area = SYSTEM_FONT_WIDTH * SYSTEM_FONT_HEIGHT * (uint64_t)x_max * (uint64_t)y_max; if (text_area != 0 && screen_area/text_area < VIEWPORT_RATIO) keep = true; } if (keep) return ST->ConOut->Mode->Mode; } /* If we reached here, then we have a high resolution screen and the text * viewport is less than 10% the screen area, so the firmware developer * screwed up. Try to switch to a better mode. Mode number 2 is first non * standard mode, which is provided by the device manufacturer, so it should * be a good mode. * Note: MaxMode is the number of modes, not the last mode. */ if (ST->ConOut->Mode->MaxMode > CONSOLE_MODE_FIRMWARE_FIRST) return CONSOLE_MODE_FIRMWARE_FIRST; /* Try again with mode different than zero (assume user requests * auto mode due to some problem with mode zero). */ if (ST->ConOut->Mode->MaxMode > CONSOLE_MODE_80_50) return CONSOLE_MODE_80_50; return CONSOLE_MODE_80_25; } static int next_mode(int64_t mode, int64_t direction) { assert(IN_SET(direction, 1, -1)); assert(ST->ConOut->Mode->MaxMode > 0); /* Always start at the beginning if we are out of range or reached the last mode already */ if (direction > 0) { if (mode < CONSOLE_MODE_RANGE_MIN || mode >= ST->ConOut->Mode->MaxMode-1) return CONSOLE_MODE_RANGE_MIN; } else if (direction < 0) { if (mode <= CONSOLE_MODE_RANGE_MIN || mode > ST->ConOut->Mode->MaxMode-1) return ST->ConOut->Mode->MaxMode-1; } else assert_not_reached(); return mode + direction; } EFI_STATUS console_set_mode(int64_t mode) { EFI_STATUS r; /* If there are no modes defined, fail immediately */ if (ST->ConOut->Mode->MaxMode <= 0) return mode == CONSOLE_MODE_KEEP ? EFI_SUCCESS : EFI_UNSUPPORTED; int64_t target, direction = 1; switch (mode) { case CONSOLE_MODE_KEEP: /* If the firmware indicates the current mode is invalid, change it anyway. */ if (ST->ConOut->Mode->Mode >= CONSOLE_MODE_RANGE_MIN && ST->ConOut->Mode->Mode < ST->ConOut->Mode->MaxMode) return EFI_SUCCESS; target = CONSOLE_MODE_RANGE_MIN; break; case CONSOLE_MODE_NEXT: target = next_mode(ST->ConOut->Mode->Mode, direction); break; case CONSOLE_MODE_AUTO: target = get_auto_mode(); break; case CONSOLE_MODE_FIRMWARE_MAX: /* Note: MaxMode is the number of modes, not the last mode. */ target = ST->ConOut->Mode->MaxMode - 1; direction = -1; /* search backwards for a working mode */ break; case CONSOLE_MODE_RANGE_MIN...CONSOLE_MODE_RANGE_MAX: target = mode; break; default: assert_not_reached(); } for (int64_t attempt = 0;; attempt++) { r = change_mode(target); if (r == EFI_SUCCESS) return EFI_SUCCESS; if (attempt >= ST->ConOut->Mode->MaxMode-1) /* give up, once we tried them all */ return r; /* If this mode is broken/unsupported, try the next. */ target = next_mode(target, direction); } } EFI_STATUS console_query_mode(size_t *x_max, size_t *y_max) { EFI_STATUS err; assert(x_max); assert(y_max); err = ST->ConOut->QueryMode(ST->ConOut, ST->ConOut->Mode->Mode, x_max, y_max); if (err != EFI_SUCCESS) { /* Fallback values mandated by UEFI spec. */ switch (ST->ConOut->Mode->Mode) { case CONSOLE_MODE_80_50: *x_max = 80; *y_max = 50; break; case CONSOLE_MODE_80_25: default: *x_max = 80; *y_max = 25; } } return err; } ubustub-1/device-path-util.c000066400000000000000000000155471504315023600162300ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-path-util.h" #include "efi-string.h" #include "string-util-fundamental.h" #include "util.h" static const EFI_DEVICE_PATH *device_path_find_end_node(const EFI_DEVICE_PATH *dp) { while (!device_path_is_end(dp)) dp = device_path_next_node(dp); return dp; } EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp) { EFI_STATUS err; EFI_DEVICE_PATH *dp; assert(file); assert(ret_dp); err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp); if (err != EFI_SUCCESS) return err; const EFI_DEVICE_PATH *end_node = device_path_find_end_node(dp); size_t file_size = strsize16(file); size_t dp_size = (uint8_t *) end_node - (uint8_t *) dp; /* Make a copy that can also hold a file media device path. */ *ret_dp = xmalloc(dp_size + file_size + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH)); dp = mempcpy(*ret_dp, dp, dp_size); FILEPATH_DEVICE_PATH *file_dp = (FILEPATH_DEVICE_PATH *) dp; file_dp->Header = (EFI_DEVICE_PATH) { .Type = MEDIA_DEVICE_PATH, .SubType = MEDIA_FILEPATH_DP, .Length = sizeof(FILEPATH_DEVICE_PATH) + file_size, }; memcpy(file_dp->PathName, file, file_size); dp = device_path_next_node(dp); *dp = DEVICE_PATH_END_NODE; return EFI_SUCCESS; } EFI_STATUS make_url_device_path(const char16_t *url, EFI_DEVICE_PATH **ret) { assert(url); assert(ret); /* Turns a URL into a simple one-element URL device path. */ _cleanup_free_ char* u = xstr16_to_ascii(url); if (!u) return EFI_INVALID_PARAMETER; size_t l = strlen8(u); size_t t = offsetof(URI_DEVICE_PATH, Uri) + l + sizeof(EFI_DEVICE_PATH); EFI_DEVICE_PATH *dp = xmalloc(t); URI_DEVICE_PATH *udp = (URI_DEVICE_PATH*) dp; udp->Header = (EFI_DEVICE_PATH) { .Type = MESSAGING_DEVICE_PATH, .SubType = MSG_URI_DP, .Length = offsetof(URI_DEVICE_PATH, Uri) + l, }; memcpy(udp->Uri, u, l); EFI_DEVICE_PATH *end = device_path_next_node(dp); *end = DEVICE_PATH_END_NODE; assert(((uint8_t*) end + sizeof(EFI_DEVICE_PATH)) == ((uint8_t*) dp + t)); *ret = TAKE_PTR(dp); return EFI_SUCCESS; } static char16_t *device_path_to_str_internal(const EFI_DEVICE_PATH *dp) { char16_t *str = NULL; for (const EFI_DEVICE_PATH *node = dp; !device_path_is_end(node); node = device_path_next_node(node)) { _cleanup_free_ char16_t *old = str; if (node->Type == END_DEVICE_PATH_TYPE && node->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) { str = xasprintf("%ls%s,", strempty(old), old ? "\\" : ""); continue; } /* Special-case this so that FilePath-only device path string look and behave nicely. */ if (node->Type == MEDIA_DEVICE_PATH && node->SubType == MEDIA_FILEPATH_DP) { str = xasprintf("%ls%s%ls", strempty(old), old ? "\\" : "", ((FILEPATH_DEVICE_PATH *) node)->PathName); continue; } /* Instead of coding all the different types and sub-types here we just use the * generic node form. This function is a best-effort for firmware that does not * provide the EFI_DEVICE_PATH_TO_TEXT_PROTOCOL after all. */ size_t size = node->Length - sizeof(EFI_DEVICE_PATH); _cleanup_free_ char16_t *hex_data = hexdump((uint8_t *) node + sizeof(EFI_DEVICE_PATH), size); str = xasprintf("%ls%sPath(%u,%u%s%ls)", strempty(old), old ? "/" : "", node->Type, node->SubType, size == 0 ? "" : ",", hex_data); } return str; } EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) { EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text; EFI_STATUS err; _cleanup_free_ char16_t *str = NULL; assert(dp); assert(ret); err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DEVICE_PATH_TO_TEXT_PROTOCOL), NULL, (void **) &dp_to_text); if (err != EFI_SUCCESS) { *ret = device_path_to_str_internal(dp); return EFI_SUCCESS; } str = dp_to_text->ConvertDevicePathToText(dp, /* DisplayOnly=*/ false, /* AllowShortcuts= */ false); if (!str) return EFI_OUT_OF_RESOURCES; *ret = TAKE_PTR(str); return EFI_SUCCESS; } bool device_path_startswith(const EFI_DEVICE_PATH *dp, const EFI_DEVICE_PATH *start) { if (!start) return true; if (!dp) return false; for (;;) { if (device_path_is_end(start)) return true; if (device_path_is_end(dp)) return false; if (start->Length != dp->Length) return false; if (memcmp(dp, start, start->Length) != 0) return false; start = device_path_next_node(start); dp = device_path_next_node(dp); } } EFI_DEVICE_PATH *device_path_replace_node( const EFI_DEVICE_PATH *path, const EFI_DEVICE_PATH *node, const EFI_DEVICE_PATH *new_node) { /* Create a new device path as a copy of path, while chopping off the remainder starting at the given * node. If new_node is provided, it is appended at the end of the new path. */ assert(path); if (!node) node = device_path_find_end_node(path); size_t len = (uint8_t *) node - (uint8_t *) path; EFI_DEVICE_PATH *ret = xmalloc(len + (new_node ? new_node->Length : 0) + sizeof(EFI_DEVICE_PATH)); EFI_DEVICE_PATH *end = mempcpy(ret, path, len); if (new_node) end = mempcpy(end, new_node, new_node->Length); *end = DEVICE_PATH_END_NODE; return ret; } size_t device_path_size(const EFI_DEVICE_PATH *dp) { const EFI_DEVICE_PATH *i = ASSERT_PTR(dp); for (; !device_path_is_end(i); i = device_path_next_node(i)) ; return (const uint8_t*) i - (const uint8_t*) dp + sizeof(EFI_DEVICE_PATH); } EFI_DEVICE_PATH *device_path_dup(const EFI_DEVICE_PATH *dp) { return xmemdup(ASSERT_PTR(dp), device_path_size(dp)); } ubustub-1/devicetree.c000066400000000000000000000235621504315023600151770ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "devicetree.h" #include "proto/dt-fixup.h" #include "util.h" #define FDT_V1_SIZE (7*4) static EFI_STATUS devicetree_allocate(struct devicetree_state *state, size_t size) { size_t pages = DIV_ROUND_UP(size, EFI_PAGE_SIZE); EFI_STATUS err; assert(state); err = BS->AllocatePages(AllocateAnyPages, EfiACPIReclaimMemory, pages, &state->addr); if (err != EFI_SUCCESS) return err; state->pages = pages; return err; } static size_t devicetree_allocated(const struct devicetree_state *state) { assert(state); return state->pages * EFI_PAGE_SIZE; } static EFI_STATUS devicetree_fixup(struct devicetree_state *state, size_t len) { EFI_DT_FIXUP_PROTOCOL *fixup; size_t size; EFI_STATUS err; assert(state); err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DT_FIXUP_PROTOCOL), NULL, (void **) &fixup); /* Skip fixup if we cannot locate device tree fixup protocol */ if (err != EFI_SUCCESS) return EFI_SUCCESS; size = devicetree_allocated(state); err = fixup->Fixup(fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size, EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY); if (err == EFI_BUFFER_TOO_SMALL) { EFI_PHYSICAL_ADDRESS oldaddr = state->addr; size_t oldpages = state->pages; void *oldptr = PHYSICAL_ADDRESS_TO_POINTER(state->addr); err = devicetree_allocate(state, size); if (err != EFI_SUCCESS) return err; memcpy(PHYSICAL_ADDRESS_TO_POINTER(state->addr), oldptr, len); err = BS->FreePages(oldaddr, oldpages); if (err != EFI_SUCCESS) return err; size = devicetree_allocated(state); err = fixup->Fixup(fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size, EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY); } return err; } EFI_STATUS devicetree_install(struct devicetree_state *state, EFI_FILE *root_dir, char16_t *name) { _cleanup_file_close_ EFI_FILE *handle = NULL; _cleanup_free_ EFI_FILE_INFO *info = NULL; size_t len; EFI_STATUS err; assert(state); assert(root_dir); assert(name); /* Capture the original value for the devicetree table. NULL is not an error in this case so we don't * need to check the return value. NULL simply means the system fw had no devicetree initially (and * is the correct value to use to return to the initial state if needed). */ state->orig = find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE)); err = root_dir->Open(root_dir, &handle, name, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY); if (err != EFI_SUCCESS) return err; err = get_file_info(handle, &info, NULL); if (err != EFI_SUCCESS) return err; if (info->FileSize < FDT_V1_SIZE || info->FileSize > 32 * 1024 * 1024) /* 32MB device tree blob doesn't seem right */ return EFI_INVALID_PARAMETER; len = info->FileSize; err = devicetree_allocate(state, len); if (err != EFI_SUCCESS) return err; err = handle->Read(handle, &len, PHYSICAL_ADDRESS_TO_POINTER(state->addr)); if (err != EFI_SUCCESS) return err; err = devicetree_fixup(state, len); if (err != EFI_SUCCESS) return err; return BS->InstallConfigurationTable( MAKE_GUID_PTR(EFI_DTB_TABLE), PHYSICAL_ADDRESS_TO_POINTER(state->addr)); } const char* devicetree_get_compatible(const void *dtb) { if ((uintptr_t) dtb % alignof(FdtHeader) != 0) return NULL; const FdtHeader *dt_header = ASSERT_PTR(dtb); if (be32toh(dt_header->magic) != UINT32_C(0xd00dfeed)) return NULL; uint32_t dt_size = be32toh(dt_header->total_size); uint32_t struct_off = be32toh(dt_header->off_dt_struct); uint32_t struct_size = be32toh(dt_header->size_dt_struct); uint32_t strings_off = be32toh(dt_header->off_dt_strings); uint32_t strings_size = be32toh(dt_header->size_dt_strings); uint32_t end; if (PTR_TO_SIZE(dtb) > SIZE_MAX - dt_size) return NULL; if (!ADD_SAFE(&end, strings_off, strings_size) || end > dt_size) return NULL; const char *strings_block = (const char *) ((const uint8_t *) dt_header + strings_off); if (struct_off % sizeof(uint32_t) != 0) return NULL; if (struct_size % sizeof(uint32_t) != 0 || !ADD_SAFE(&end, struct_off, struct_size) || end > strings_off) return NULL; const uint32_t *cursor = (const uint32_t *) ((const uint8_t *) dt_header + struct_off); size_t size_words = struct_size / sizeof(uint32_t); size_t len, name_off, len_words, s; for (size_t i = 0; i < end; i++) { switch (be32toh(cursor[i])) { case FDT_BEGIN_NODE: if (i >= size_words || cursor[++i] != 0) return NULL; break; case FDT_NOP: break; case FDT_PROP: /* At least 3 words should present: len, name_off, c (nul-terminated string always has non-zero length) */ if (i + 3 >= size_words) return NULL; len = be32toh(cursor[++i]); name_off = be32toh(cursor[++i]); len_words = DIV_ROUND_UP(len, sizeof(uint32_t)); if (ADD_SAFE(&s, name_off, STRLEN("compatible")) && s < strings_size && streq8(strings_block + name_off, "compatible")) { const char *c = (const char *) &cursor[++i]; if (len == 0 || i + len_words > size_words || c[len - 1] != '\0') c = NULL; return c; } i += len_words; break; default: return NULL; } } return NULL; } bool firmware_devicetree_exists(void) { return !!find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE)); } /* This function checks if the firmware provided DeviceTree * and a UKI provided DeviceTree contain the same first entry * on their respective "compatible" fields (which usually defines * the actual device model). More specifically, given the FW/UKI * "compatible" property pair: * * compatible = "string1", "string2"; * compatible = "string1", "string3"; * * the function reports a match, while for * * compatible = "string1", "string3"; * compatible = "string2", "string1"; * * it reports a mismatch. * * Other entries might refer to SoC and therefore can't be used for matching */ EFI_STATUS devicetree_match(const void *uki_dtb, size_t uki_dtb_length) { const void *fw_dtb = find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE)); if (!fw_dtb) return EFI_UNSUPPORTED; const char *fw_compat = devicetree_get_compatible(fw_dtb); if (!fw_compat) return EFI_UNSUPPORTED; return devicetree_match_by_compatible(uki_dtb, uki_dtb_length, fw_compat); } EFI_STATUS devicetree_match_by_compatible(const void *uki_dtb, size_t uki_dtb_length, const char *compat) { if ((uintptr_t) uki_dtb % alignof(FdtHeader) != 0) return EFI_INVALID_PARAMETER; const FdtHeader *dt_header = ASSERT_PTR(uki_dtb); if (uki_dtb_length < sizeof(FdtHeader) || uki_dtb_length < be32toh(dt_header->total_size)) return EFI_INVALID_PARAMETER; if (!compat) return EFI_INVALID_PARAMETER; const char *dt_compat = devicetree_get_compatible(uki_dtb); if (!dt_compat) return EFI_INVALID_PARAMETER; /* Only matches the first compatible string from each DT */ return streq8(dt_compat, compat) ? EFI_SUCCESS : EFI_NOT_FOUND; } EFI_STATUS devicetree_install_from_memory( struct devicetree_state *state, const void *dtb_buffer, size_t dtb_length) { EFI_STATUS err; assert(state); assert(dtb_buffer && dtb_length > 0); /* Capture the original value for the devicetree table. NULL is not an error in this case so we don't * need to check the return value. NULL simply means the system fw had no devicetree initially (and * is the correct value to use to return to the initial state if needed). */ state->orig = find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE)); err = devicetree_allocate(state, dtb_length); if (err != EFI_SUCCESS) return err; memcpy(PHYSICAL_ADDRESS_TO_POINTER(state->addr), dtb_buffer, dtb_length); err = devicetree_fixup(state, dtb_length); if (err != EFI_SUCCESS) return err; return BS->InstallConfigurationTable( MAKE_GUID_PTR(EFI_DTB_TABLE), PHYSICAL_ADDRESS_TO_POINTER(state->addr)); } void devicetree_cleanup(struct devicetree_state *state) { EFI_STATUS err; if (!state->pages) return; err = BS->InstallConfigurationTable(MAKE_GUID_PTR(EFI_DTB_TABLE), state->orig); /* don't free the current device tree if we can't reinstate the old one */ if (err != EFI_SUCCESS) return; BS->FreePages(state->addr, state->pages); state->pages = 0; } ubustub-1/edid.c000066400000000000000000000062131504315023600137570ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "edid.h" #include "efivars-fundamental.h" #include "proto/edid-discovered.h" #include "util.h" #define EDID_FIXED_HEADER_PATTERN "\x00\xFF\xFF\xFF\xFF\xFF\xFF" assert_cc(sizeof_field(EdidHeader, pattern) == sizeof(EDID_FIXED_HEADER_PATTERN)); int edid_parse_blob(const void *blob, size_t blob_size, EdidHeader *ret_header) { assert(ret_header); /* EDID size is at least 128 as per the specification */ if (blob_size < 128) return -EINVAL; const EdidHeader *edid_header = ASSERT_PTR(blob); if (memcmp(edid_header->pattern, EDID_FIXED_HEADER_PATTERN, sizeof(EDID_FIXED_HEADER_PATTERN)) != 0) return -EINVAL; *ret_header = (EdidHeader) { .pattern = EDID_FIXED_HEADER_PATTERN, .manufacturer_id = be16toh(edid_header->manufacturer_id), .manufacturer_product_code = le16toh(edid_header->manufacturer_product_code), .serial_number = le32toh(edid_header->serial_number), .week_of_manufacture = edid_header->week_of_manufacture, .year_of_manufacture = edid_header->year_of_manufacture, .edid_version = edid_header->edid_version, .edid_revision = edid_header->edid_revision, }; return 0; } int edid_get_panel_id(const EdidHeader *edid_header, char16_t ret_panel[static 8]) { assert(edid_header); assert(ret_panel); for (size_t i = 0; i < 3; i++) { uint8_t letter = (edid_header->manufacturer_id >> (5 * i)) & 0b11111; if (letter > 0b11010) return -EINVAL; ret_panel[2 - i] = letter + 'A' - 1; } ret_panel[3] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >> 12) & 0x0F]; ret_panel[4] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >> 8) & 0x0F]; ret_panel[5] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >> 4) & 0x0F]; ret_panel[6] = LOWERCASE_HEXDIGITS[(edid_header->manufacturer_product_code >> 0) & 0x0F]; ret_panel[7] = L'\0'; return 0; } EFI_STATUS edid_get_discovered_panel_id(char16_t **ret_panel) { assert(ret_panel); EFI_EDID_DISCOVERED_PROTOCOL *edid_discovered = NULL; EFI_STATUS status = BS->LocateProtocol(MAKE_GUID_PTR(EFI_EDID_DISCOVERED_PROTOCOL), NULL, (void **) &edid_discovered); if (EFI_STATUS_IS_ERROR(status)) return status; if (!edid_discovered) return EFI_UNSUPPORTED; if (!edid_discovered->Edid) return EFI_UNSUPPORTED; if (edid_discovered->SizeOfEdid == 0) return EFI_UNSUPPORTED; EdidHeader header; if (edid_parse_blob(edid_discovered->Edid, edid_discovered->SizeOfEdid, &header) < 0) return EFI_INCOMPATIBLE_VERSION; _cleanup_free_ char16_t *panel = xnew0(char16_t, 8); if (edid_get_panel_id(&header, panel) < 0) return EFI_INVALID_PARAMETER; *ret_panel = TAKE_PTR(panel); return EFI_SUCCESS; } ubustub-1/efi-efivars.c000066400000000000000000000162041504315023600152530ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "efi-efivars.h" #include "efi-string.h" #include "util.h" EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags) { assert(vendor); assert(name); assert(buf || size == 0); flags |= EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; return RT->SetVariable((char16_t *) name, (EFI_GUID *) vendor, flags, size, (void *) buf); } EFI_STATUS efivar_set_str16(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags) { assert(vendor); assert(name); return efivar_set_raw(vendor, name, value, value ? strsize16(value) : 0, flags); } EFI_STATUS efivar_set_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t i, uint32_t flags) { assert(vendor); assert(name); _cleanup_free_ char16_t *str = xasprintf("%" PRIu64, i); return efivar_set_str16(vendor, name, str, flags); } EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags) { uint8_t buf[4]; assert(vendor); assert(name); buf[0] = (uint8_t)(value >> 0U & 0xFF); buf[1] = (uint8_t)(value >> 8U & 0xFF); buf[2] = (uint8_t)(value >> 16U & 0xFF); buf[3] = (uint8_t)(value >> 24U & 0xFF); return efivar_set_raw(vendor, name, buf, sizeof(buf), flags); } EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags) { uint8_t buf[8]; assert(vendor); assert(name); buf[0] = (uint8_t)(value >> 0U & 0xFF); buf[1] = (uint8_t)(value >> 8U & 0xFF); buf[2] = (uint8_t)(value >> 16U & 0xFF); buf[3] = (uint8_t)(value >> 24U & 0xFF); buf[4] = (uint8_t)(value >> 32U & 0xFF); buf[5] = (uint8_t)(value >> 40U & 0xFF); buf[6] = (uint8_t)(value >> 48U & 0xFF); buf[7] = (uint8_t)(value >> 56U & 0xFF); return efivar_set_raw(vendor, name, buf, sizeof(buf), flags); } EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags) { EFI_STATUS err; assert(vendor); assert(name); /* We could be wiping a non-volatile variable here and the spec makes no guarantees that won't incur * in an extra write (and thus wear out). So check and clear only if needed. */ err = efivar_get_raw(vendor, name, NULL, NULL); if (err == EFI_SUCCESS) return efivar_set_raw(vendor, name, NULL, 0, flags); return err; } EFI_STATUS efivar_get_str16(const EFI_GUID *vendor, const char16_t *name, char16_t **ret) { _cleanup_free_ char16_t *buf = NULL; EFI_STATUS err; char16_t *val; size_t size; assert(vendor); assert(name); err = efivar_get_raw(vendor, name, (void**) &buf, &size); if (err != EFI_SUCCESS) return err; /* Make sure there are no incomplete characters in the buffer */ if ((size % sizeof(char16_t)) != 0) return EFI_INVALID_PARAMETER; if (!ret) return EFI_SUCCESS; /* Return buffer directly if it happens to be NUL terminated already */ if (size >= sizeof(char16_t) && buf[size / sizeof(char16_t) - 1] == 0) { *ret = TAKE_PTR(buf); return EFI_SUCCESS; } /* Make sure a terminating NUL is available at the end */ val = xmalloc(size + sizeof(char16_t)); memcpy(val, buf, size); val[size / sizeof(char16_t) - 1] = 0; /* NUL terminate */ *ret = val; return EFI_SUCCESS; } EFI_STATUS efivar_get_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret) { EFI_STATUS err; assert(vendor); assert(name); _cleanup_free_ char16_t *val = NULL; err = efivar_get_str16(vendor, name, &val); if (err != EFI_SUCCESS) return err; uint64_t u; if (!parse_number16(val, &u, NULL)) return EFI_INVALID_PARAMETER; if (ret) *ret = u; return EFI_SUCCESS; } EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret) { _cleanup_free_ uint8_t *buf = NULL; size_t size; EFI_STATUS err; assert(vendor); assert(name); err = efivar_get_raw(vendor, name, (void**) &buf, &size); if (err != EFI_SUCCESS) return err; if (size != sizeof(uint32_t)) return EFI_BUFFER_TOO_SMALL; if (ret) *ret = (uint32_t) buf[0] << 0U | (uint32_t) buf[1] << 8U | (uint32_t) buf[2] << 16U | (uint32_t) buf[3] << 24U; return EFI_SUCCESS; } EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret) { _cleanup_free_ uint8_t *buf = NULL; size_t size; EFI_STATUS err; assert(vendor); assert(name); err = efivar_get_raw(vendor, name, (void**) &buf, &size); if (err != EFI_SUCCESS) return err; if (size != sizeof(uint64_t)) return EFI_BUFFER_TOO_SMALL; if (ret) *ret = (uint64_t) buf[0] << 0U | (uint64_t) buf[1] << 8U | (uint64_t) buf[2] << 16U | (uint64_t) buf[3] << 24U | (uint64_t) buf[4] << 32U | (uint64_t) buf[5] << 40U | (uint64_t) buf[6] << 48U | (uint64_t) buf[7] << 56U; return EFI_SUCCESS; } EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, void **ret_data, size_t *ret_size) { EFI_STATUS err; assert(vendor); assert(name); size_t size = 0; err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, NULL); if (err != EFI_BUFFER_TOO_SMALL) return err; _cleanup_free_ void *buf = xmalloc(size); err = RT->GetVariable((char16_t *) name, (EFI_GUID *) vendor, NULL, &size, buf); if (err != EFI_SUCCESS) return err; if (ret_data) *ret_data = TAKE_PTR(buf); if (ret_size) *ret_size = size; return EFI_SUCCESS; } EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret) { _cleanup_free_ uint8_t *b = NULL; size_t size; EFI_STATUS err; assert(vendor); assert(name); err = efivar_get_raw(vendor, name, (void**) &b, &size); if (err != EFI_SUCCESS) return err; if (ret) *ret = *b > 0; return EFI_SUCCESS; } uint64_t get_os_indications_supported(void) { uint64_t osind; EFI_STATUS err; /* Returns the supported OS indications. If we can't acquire it, returns a zeroed out mask, i.e. no * supported features. */ err = efivar_get_uint64_le(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"OsIndicationsSupported", &osind); if (err != EFI_SUCCESS) return 0; return osind; } ubustub-1/efi-firmware.c000066400000000000000000000043101504315023600154230ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "efi-firmware.h" #include "efi-string.h" static bool efifw_validate_header( const void *blob, size_t blob_len, const char **ret_fwid, const char **ret_payload) { if ((uintptr_t) blob % alignof(EfiFwHeader) != 0) return false; size_t base_sz = offsetof(EfiFwHeader, payload); /* at least the base size of the header must be in memory */ if (blob_len < base_sz) return false; const EfiFwHeader *fw_header = ASSERT_PTR(blob); if (fw_header->magic != FWHEADERMAGIC) return false; uint32_t header_len = fw_header->header_len; /* header_len must not be malformed */ if (header_len < base_sz) return false; uint32_t fwid_len = fw_header->fwid_len; uint32_t payload_len = fw_header->payload_len; size_t total_computed_size; /* check for unusually large values of payload_len, header_len or fwid_len */ if (!ADD_SAFE(&total_computed_size, header_len, fwid_len) || !ADD_SAFE(&total_computed_size, total_computed_size, payload_len)) return false; /* see if entire size of the base header is present in memory */ if (blob_len < total_computed_size) return false; const char *fwid = (const char*) blob + header_len; const char *payload = fwid + fwid_len; /* check that fwid points to a NUL terminated string */ if (memchr(fwid, 0, fwid_len) != fwid + fwid_len - 1) return false; if (ret_fwid) *ret_fwid = fwid; if (ret_payload) *ret_payload = payload; return true; } EFI_STATUS efi_firmware_match_by_fwid( const void *blob, size_t blob_len, const char *fwid) { assert(blob); assert(fwid); const char *blob_fwid; if (!efifw_validate_header(blob, blob_len, &blob_fwid, NULL)) return EFI_INVALID_PARAMETER; return streq8(blob_fwid, fwid) ? EFI_SUCCESS : EFI_NOT_FOUND; } ubustub-1/efi-log.c000066400000000000000000000065321504315023600144000ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "efi-log.h" #include "proto/rng.h" #include "util.h" static unsigned log_count = 0; bool log_isdebug = false; void freeze(void) { for (;;) BS->Stall(60 * 1000 * 1000); } _noreturn_ static void panic(const char16_t *message) { if (ST->ConOut->Mode->CursorColumn > 0) ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n"); ST->ConOut->SetAttribute(ST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTRED, EFI_BLACK)); ST->ConOut->OutputString(ST->ConOut, (char16_t *) message); freeze(); } void efi_assert(const char *expr, const char *file, unsigned line, const char *function) { static bool asserting = false; /* Let's be paranoid. */ if (asserting) panic(u"systemd-boot: Nested assertion failure, halting."); asserting = true; log_error("systemd-boot: Assertion '%s' failed at %s:%u@%s, halting.", expr, file, line, function); freeze(); } EFI_STATUS log_internal(EFI_STATUS status, uint8_t text_color, const char *format, ...) { assert(format); int32_t attr = ST->ConOut->Mode->Attribute; if (ST->ConOut->Mode->CursorColumn > 0) ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n"); ST->ConOut->SetAttribute(ST->ConOut, EFI_TEXT_ATTR(text_color, EFI_BLACK)); va_list ap; va_start(ap, format); vprintf_status(status, format, ap); va_end(ap); ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n"); ST->ConOut->SetAttribute(ST->ConOut, attr); log_count++; return status; } void log_wait(void) { if (log_count == 0) return; BS->Stall(MIN(4u, log_count) * 2500 * 1000); log_count = 0; } _used_ intptr_t __stack_chk_guard = (intptr_t) 0x70f6967de78acae3; /* We can only set a random stack canary if this function attribute is available, * otherwise this may create a stack check fail. */ #if STACK_PROTECTOR_RANDOM void __stack_chk_guard_init(void) { EFI_RNG_PROTOCOL *rng; if (BS->LocateProtocol(MAKE_GUID_PTR(EFI_RNG_PROTOCOL), NULL, (void **) &rng) == EFI_SUCCESS) (void) rng->GetRNG(rng, NULL, sizeof(__stack_chk_guard), (void *) &__stack_chk_guard); else /* Better than no extra entropy. */ __stack_chk_guard ^= (intptr_t) __executable_start; } #endif _used_ _noreturn_ void __stack_chk_fail(void); _used_ _noreturn_ void __stack_chk_fail_local(void); void __stack_chk_fail(void) { panic(u"systemd-boot: Stack check failed, halting."); } void __stack_chk_fail_local(void) { __stack_chk_fail(); } /* Called by libgcc for some fatal errors like integer overflow with -ftrapv. */ _used_ _noreturn_ void abort(void); void abort(void) { panic(u"systemd-boot: Unknown error, halting."); } #if defined(__ARM_EABI__) /* These override the (weak) div0 handlers from libgcc as they would otherwise call raise() instead. */ _used_ _noreturn_ int __aeabi_idiv0(int return_value); _used_ _noreturn_ long long __aeabi_ldiv0(long long return_value); int __aeabi_idiv0(int return_value) { panic(u"systemd-boot: Division by zero, halting."); } long long __aeabi_ldiv0(long long return_value) { panic(u"systemd-boot: Division by zero, halting."); } #endif ubustub-1/efi-string.c000066400000000000000000001165751504315023600151360ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "efi-string.h" #include "proto/simple-text-io.h" #include "util.h" /* String functions for both char and char16_t that should behave the same way as their respective * counterpart in userspace. Where it makes sense, these accept NULL and do something sensible whereas * userspace does not allow for this (strlen8(NULL) returns 0 like strlen_ptr(NULL) for example). To make it * easier to tell in code which kind of string they work on, we use 8/16 suffixes. This also makes is easier * to unit test them. */ #define DEFINE_STRNLEN(type, name) \ size_t name(const type *s, size_t n) { \ if (!s) \ return 0; \ \ size_t len = 0; \ while (len < n && *s) { \ s++; \ len++; \ } \ \ return len; \ } DEFINE_STRNLEN(char, strnlen8); DEFINE_STRNLEN(char16_t, strnlen16); #define TOLOWER(c) \ ({ \ typeof(c) _c = (c); \ (_c >= 'A' && _c <= 'Z') ? _c + ('a' - 'A') : _c; \ }) #define DEFINE_STRTOLOWER(type, name) \ type* name(type *s) { \ if (!s) \ return NULL; \ for (type *p = s; *p; p++) \ *p = TOLOWER(*p); \ return s; \ } DEFINE_STRTOLOWER(char, strtolower8); DEFINE_STRTOLOWER(char16_t, strtolower16); #define DEFINE_STRNCASECMP(type, name, tolower) \ int name(const type *s1, const type *s2, size_t n) { \ if (!s1 || !s2) \ return CMP(s1, s2); \ \ while (n > 0) { \ type c1 = *s1, c2 = *s2; \ if (tolower) { \ c1 = TOLOWER(c1); \ c2 = TOLOWER(c2); \ } \ if (!c1 || c1 != c2) \ return CMP(c1, c2); \ \ s1++; \ s2++; \ n--; \ } \ \ return 0; \ } DEFINE_STRNCASECMP(char, strncmp8, false); DEFINE_STRNCASECMP(char16_t, strncmp16, false); DEFINE_STRNCASECMP(char, strncasecmp8, true); DEFINE_STRNCASECMP(char16_t, strncasecmp16, true); #define DEFINE_STRCPY(type, name) \ type *name(type * restrict dest, const type * restrict src) { \ type *ret = ASSERT_PTR(dest); \ \ if (!src) { \ *dest = '\0'; \ return ret; \ } \ \ while (*src) { \ *dest = *src; \ dest++; \ src++; \ } \ \ *dest = '\0'; \ return ret; \ } DEFINE_STRCPY(char, strcpy8); DEFINE_STRCPY(char16_t, strcpy16); #define DEFINE_STRCHR(type, name) \ type *name(const type *s, type c) { \ if (!s) \ return NULL; \ \ while (*s) { \ if (*s == c) \ return (type *) s; \ s++; \ } \ \ return c ? NULL : (type *) s; \ } DEFINE_STRCHR(char, strchr8); DEFINE_STRCHR(char16_t, strchr16); #define DEFINE_STRNDUP(type, name, len_func) \ type *name(const type *s, size_t n) { \ if (!s) \ return NULL; \ \ size_t len = len_func(s, n); \ size_t size = len * sizeof(type); \ \ type *dup = xmalloc(size + sizeof(type)); \ if (size > 0) \ memcpy(dup, s, size); \ dup[len] = '\0'; \ \ return dup; \ } DEFINE_STRNDUP(char, xstrndup8, strnlen8); DEFINE_STRNDUP(char16_t, xstrndup16, strnlen16); static unsigned utf8_to_unichar(const char *utf8, size_t n, char32_t *c) { char32_t unichar; unsigned len; assert(utf8); assert(c); if (!(utf8[0] & 0x80)) { *c = utf8[0]; return 1; } else if ((utf8[0] & 0xe0) == 0xc0) { len = 2; unichar = utf8[0] & 0x1f; } else if ((utf8[0] & 0xf0) == 0xe0) { len = 3; unichar = utf8[0] & 0x0f; } else if ((utf8[0] & 0xf8) == 0xf0) { len = 4; unichar = utf8[0] & 0x07; } else if ((utf8[0] & 0xfc) == 0xf8) { len = 5; unichar = utf8[0] & 0x03; } else if ((utf8[0] & 0xfe) == 0xfc) { len = 6; unichar = utf8[0] & 0x01; } else { *c = UINT32_MAX; return 1; } if (len > n) { *c = UINT32_MAX; return len; } for (unsigned i = 1; i < len; i++) { if ((utf8[i] & 0xc0) != 0x80) { *c = UINT32_MAX; return len; } unichar <<= 6; unichar |= utf8[i] & 0x3f; } *c = unichar; return len; } /* Convert UTF-8 to UCS-2, skipping any invalid or short byte sequences. */ char16_t *xstrn8_to_16(const char *str8, size_t n) { assert(str8 || n == 0); if (n == SIZE_MAX) n = strlen8(str8); size_t i = 0; char16_t *str16 = xnew(char16_t, n + 1); while (n > 0 && *str8 != '\0') { char32_t unichar; size_t utf8len = utf8_to_unichar(str8, n, &unichar); str8 += utf8len; n = LESS_BY(n, utf8len); switch (unichar) { case 0 ... 0xd7ffU: case 0xe000U ... 0xffffU: str16[i++] = unichar; break; } } str16[i] = u'\0'; return str16; } char *xstrn16_to_ascii(const char16_t *str16, size_t n) { assert(str16 || n == 0); if (n == SIZE_MAX) n = strlen16(str16); _cleanup_free_ char *str8 = xnew(char, n + 1); size_t i = 0; while (n > 0 && *str16 != u'\0') { if ((uint16_t) *str16 > 127U) /* Not ASCII? Fail! */ return NULL; str8[i++] = (char) (uint16_t) *str16; str16++; n--; } str8[i] = '\0'; return TAKE_PTR(str8); } char* startswith8(const char *s, const char *prefix) { size_t l; assert(prefix); if (!s) return NULL; l = strlen8(prefix); if (!strneq8(s, prefix, l)) return NULL; return (char*) s + l; } static bool efi_fnmatch_prefix(const char16_t *p, const char16_t *h, const char16_t **ret_p, const char16_t **ret_h) { assert(p); assert(h); assert(ret_p); assert(ret_h); for (;; p++, h++) switch (*p) { case '\0': /* End of pattern. Check that haystack is now empty. */ return *h == '\0'; case '\\': p++; if (*p == '\0' || *p != *h) /* Trailing escape or no match. */ return false; break; case '?': if (*h == '\0') /* Early end of haystack. */ return false; break; case '*': /* Point ret_p at the remainder of the pattern. */ while (*p == '*') p++; *ret_p = p; *ret_h = h; return true; case '[': if (*h == '\0') /* Early end of haystack. */ return false; bool first = true, can_range = true, match = false; for (;; first = false) { p++; if (*p == '\0') return false; if (*p == '\\') { p++; if (*p == '\0') return false; if (*p == *h) match = true; can_range = true; continue; } /* End of set unless it's the first char. */ if (*p == ']' && !first) break; /* Range pattern if '-' is not first or last in set. */ if (*p == '-' && can_range && !first && *(p + 1) != ']') { char16_t low = *(p - 1); p++; if (*p == '\\') p++; if (*p == '\0') return false; if (low <= *h && *h <= *p) match = true; /* Ranges cannot be chained: [a-c-f] == [-abcf] */ can_range = false; continue; } if (*p == *h) match = true; can_range = true; } if (!match) return false; break; default: if (*p != *h) /* Single char mismatch. */ return false; } } /* Patterns are fnmatch-compatible (with reduced feature support). */ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) { /* Patterns can be considered as simple patterns (without '*') concatenated by '*'. By doing so we * simply have to make sure the very first simple pattern matches the start of haystack. Then we just * look for the remaining simple patterns *somewhere* within the haystack (in order) as any extra * characters in between would be matches by the '*'. We then only have to ensure that the very last * simple pattern matches at the actual end of the haystack. * * This means we do not need to use backtracking which could have catastrophic runtimes with the * right input data. */ for (bool first = true;;) { const char16_t *pattern_tail = NULL, *haystack_tail = NULL; bool match = efi_fnmatch_prefix(pattern, haystack, &pattern_tail, &haystack_tail); if (first) { if (!match) /* Initial simple pattern must match. */ return false; if (!pattern_tail) /* No '*' was in pattern, we can return early. */ return true; first = false; } if (pattern_tail) { assert(match); pattern = pattern_tail; haystack = haystack_tail; } else { /* If we have a match this must be at the end of the haystack. Note that * efi_fnmatch_prefix compares the NUL-bytes at the end, so we cannot match the end * of pattern in the middle of haystack). */ if (match || *haystack == '\0') return match; /* Match one character using '*'. */ haystack++; } } } #define DEFINE_PARSE_NUMBER(type, name) \ bool name(const type *s, uint64_t *ret_u, const type **ret_tail) { \ assert(ret_u); \ \ if (!s) \ return false; \ \ /* Need at least one digit. */ \ if (*s < '0' || *s > '9') \ return false; \ \ uint64_t u = 0; \ while (*s >= '0' && *s <= '9') { \ if (!MUL_ASSIGN_SAFE(&u, 10)) \ return false; \ if (!INC_SAFE(&u, *s - '0')) \ return false; \ s++; \ } \ \ if (!ret_tail && *s != '\0') \ return false; \ \ *ret_u = u; \ if (ret_tail) \ *ret_tail = s; \ return true; \ } DEFINE_PARSE_NUMBER(char, parse_number8); DEFINE_PARSE_NUMBER(char16_t, parse_number16); bool parse_boolean(const char *v, bool *ret) { assert(ret); if (!v) return false; if (streq8(v, "1") || streq8(v, "yes") || streq8(v, "y") || streq8(v, "true") || streq8(v, "t") || streq8(v, "on")) { *ret = true; return true; } if (streq8(v, "0") || streq8(v, "no") || streq8(v, "n") || streq8(v, "false") || streq8(v, "f") || streq8(v, "off")) { *ret = false; return true; } return false; } char* line_get_key_value(char *s, const char *sep, size_t *pos, char **ret_key, char **ret_value) { char *line, *value; size_t linelen; assert(s); assert(sep); assert(pos); assert(ret_key); assert(ret_value); for (;;) { line = s + *pos; if (*line == '\0') return NULL; linelen = 0; while (line[linelen] && !strchr8("\n\r", line[linelen])) linelen++; /* move pos to next line */ *pos += linelen; if (s[*pos]) (*pos)++; /* empty line */ if (linelen == 0) continue; /* terminate line */ line[linelen] = '\0'; /* remove leading whitespace */ while (linelen > 0 && strchr8(" \t", *line)) { line++; linelen--; } /* remove trailing whitespace */ while (linelen > 0 && strchr8(" \t", line[linelen - 1])) linelen--; line[linelen] = '\0'; if (*line == '#') continue; /* split key/value */ value = line; while (*value && !strchr8(sep, *value)) value++; if (*value == '\0') continue; *value = '\0'; value++; while (*value && strchr8(sep, *value)) value++; /* unquote */ if (value[0] == '"' && line[linelen - 1] == '"') { value++; line[linelen - 1] = '\0'; } *ret_key = line; *ret_value = value; return line; } } char16_t *hexdump(const void *data, size_t size) { static const char hex[] = "0123456789abcdef"; const uint8_t *d = data; assert(data || size == 0); char16_t *buf = xnew(char16_t, size * 2 + 1); for (size_t i = 0; i < size; i++) { buf[i * 2] = hex[d[i] >> 4]; buf[i * 2 + 1] = hex[d[i] & 0x0F]; } buf[size * 2] = 0; return buf; } static const char * const warn_table[] = { [EFI_SUCCESS] = "Success", [EFI_WARN_UNKNOWN_GLYPH] = "Unknown glyph", [EFI_WARN_DELETE_FAILURE] = "Delete failure", [EFI_WARN_WRITE_FAILURE] = "Write failure", [EFI_WARN_BUFFER_TOO_SMALL] = "Buffer too small", [EFI_WARN_STALE_DATA] = "Stale data", [EFI_WARN_FILE_SYSTEM] = "File system", [EFI_WARN_RESET_REQUIRED] = "Reset required", }; /* Errors have MSB set, remove it to keep the table compact. */ #define NOERR(err) ((err) & ~EFI_ERROR_MASK) static const char * const err_table[] = { [NOERR(EFI_ERROR_MASK)] = "Error", [NOERR(EFI_LOAD_ERROR)] = "Load error", [NOERR(EFI_INVALID_PARAMETER)] = "Invalid parameter", [NOERR(EFI_UNSUPPORTED)] = "Unsupported", [NOERR(EFI_BAD_BUFFER_SIZE)] = "Bad buffer size", [NOERR(EFI_BUFFER_TOO_SMALL)] = "Buffer too small", [NOERR(EFI_NOT_READY)] = "Not ready", [NOERR(EFI_DEVICE_ERROR)] = "Device error", [NOERR(EFI_WRITE_PROTECTED)] = "Write protected", [NOERR(EFI_OUT_OF_RESOURCES)] = "Out of resources", [NOERR(EFI_VOLUME_CORRUPTED)] = "Volume corrupt", [NOERR(EFI_VOLUME_FULL)] = "Volume full", [NOERR(EFI_NO_MEDIA)] = "No media", [NOERR(EFI_MEDIA_CHANGED)] = "Media changed", [NOERR(EFI_NOT_FOUND)] = "Not found", [NOERR(EFI_ACCESS_DENIED)] = "Access denied", [NOERR(EFI_NO_RESPONSE)] = "No response", [NOERR(EFI_NO_MAPPING)] = "No mapping", [NOERR(EFI_TIMEOUT)] = "Time out", [NOERR(EFI_NOT_STARTED)] = "Not started", [NOERR(EFI_ALREADY_STARTED)] = "Already started", [NOERR(EFI_ABORTED)] = "Aborted", [NOERR(EFI_ICMP_ERROR)] = "ICMP error", [NOERR(EFI_TFTP_ERROR)] = "TFTP error", [NOERR(EFI_PROTOCOL_ERROR)] = "Protocol error", [NOERR(EFI_INCOMPATIBLE_VERSION)] = "Incompatible version", [NOERR(EFI_SECURITY_VIOLATION)] = "Security violation", [NOERR(EFI_CRC_ERROR)] = "CRC error", [NOERR(EFI_END_OF_MEDIA)] = "End of media", [NOERR(EFI_ERROR_RESERVED_29)] = "Reserved (29)", [NOERR(EFI_ERROR_RESERVED_30)] = "Reserved (30)", [NOERR(EFI_END_OF_FILE)] = "End of file", [NOERR(EFI_INVALID_LANGUAGE)] = "Invalid language", [NOERR(EFI_COMPROMISED_DATA)] = "Compromised data", [NOERR(EFI_IP_ADDRESS_CONFLICT)] = "IP address conflict", [NOERR(EFI_HTTP_ERROR)] = "HTTP error", }; static const char *status_to_string(EFI_STATUS status) { if (status <= ELEMENTSOF(warn_table) - 1) return warn_table[status]; if (status >= EFI_ERROR_MASK && status <= ((ELEMENTSOF(err_table) - 1) | EFI_ERROR_MASK)) return err_table[NOERR(status)]; return NULL; } typedef struct { size_t padded_len; /* Field width in printf. */ size_t len; /* Precision in printf. */ bool pad_zero; bool align_left; bool alternative_form; bool long_arg; bool longlong_arg; bool have_field_width; const char *str; const wchar_t *wstr; /* For numbers. */ bool is_signed; bool lowercase; int8_t base; char sign_pad; /* For + and (space) flags. */ } SpecifierContext; typedef struct { char16_t stack_buf[128]; /* We use stack_buf first to avoid allocations in most cases. */ char16_t *dyn_buf; /* Allocated buf or NULL if stack_buf is used. */ char16_t *buf; /* Points to the current active buf. */ size_t n_buf; /* Len of buf (in char16_t's, not bytes!). */ size_t n; /* Used len of buf (in char16_t's). This is always n)); if (need < ctx->n_buf) return; /* Greedily allocate if we can. */ if (!MUL_SAFE(&ctx->n_buf, need, 2)) ctx->n_buf = need; /* We cannot use realloc here as ctx->buf may be ctx->stack_buf, which we cannot free. */ char16_t *new_buf = xnew(char16_t, ctx->n_buf); memcpy(new_buf, ctx->buf, ctx->n * sizeof(*ctx->buf)); free(ctx->dyn_buf); ctx->buf = ctx->dyn_buf = new_buf; } static void push_padding(FormatContext *ctx, char pad, size_t len) { assert(ctx); while (len > 0) { len--; ctx->buf[ctx->n++] = pad; } } static bool push_str(FormatContext *ctx, SpecifierContext *sp) { assert(ctx); assert(sp); sp->padded_len = LESS_BY(sp->padded_len, sp->len); grow_buf(ctx, sp->padded_len + sp->len); if (!sp->align_left) push_padding(ctx, ' ', sp->padded_len); /* In userspace unit tests we cannot just memcpy() the wide string. */ if (sp->wstr && sizeof(wchar_t) == sizeof(char16_t)) { memcpy(ctx->buf + ctx->n, sp->wstr, sp->len * sizeof(*sp->wstr)); ctx->n += sp->len; } else { assert(sp->str || sp->wstr); for (size_t i = 0; i < sp->len; i++) ctx->buf[ctx->n++] = sp->str ? sp->str[i] : sp->wstr[i]; } if (sp->align_left) push_padding(ctx, ' ', sp->padded_len); assert(ctx->n < ctx->n_buf); return true; } static bool push_num(FormatContext *ctx, SpecifierContext *sp, uint64_t u) { const char *digits = sp->lowercase ? "0123456789abcdef" : "0123456789ABCDEF"; char16_t tmp[32]; size_t n = 0; assert(ctx); assert(sp); assert(IN_SET(sp->base, 10, 16)); /* "%.0u" prints nothing if value is 0. */ if (u == 0 && sp->len == 0) return true; if (sp->is_signed && (int64_t) u < 0) { /* We cannot just do "u = -(int64_t)u" here because -INT64_MIN overflows. */ uint64_t rem = -((int64_t) u % sp->base); u = (int64_t) u / -sp->base; tmp[n++] = digits[rem]; sp->sign_pad = '-'; } while (u > 0 || n == 0) { uint64_t rem = u % sp->base; u /= sp->base; tmp[n++] = digits[rem]; } /* Note that numbers never get truncated! */ size_t prefix = (sp->sign_pad != 0 ? 1 : 0) + (sp->alternative_form ? 2 : 0); size_t number_len = prefix + MAX(n, sp->len); grow_buf(ctx, MAX(sp->padded_len, number_len)); size_t padding = 0; if (sp->pad_zero) /* Leading zeroes go after the sign or 0x prefix. */ number_len = MAX(number_len, sp->padded_len); else padding = LESS_BY(sp->padded_len, number_len); if (!sp->align_left) push_padding(ctx, ' ', padding); if (sp->sign_pad != 0) ctx->buf[ctx->n++] = sp->sign_pad; if (sp->alternative_form) { ctx->buf[ctx->n++] = '0'; ctx->buf[ctx->n++] = sp->lowercase ? 'x' : 'X'; } push_padding(ctx, '0', LESS_BY(number_len, n + prefix)); while (n > 0) ctx->buf[ctx->n++] = tmp[--n]; if (sp->align_left) push_padding(ctx, ' ', padding); assert(ctx->n < ctx->n_buf); return true; } /* This helps unit testing. */ #define NULLSTR "(null)" #define wcsnlen strnlen16 static bool handle_format_specifier(FormatContext *ctx, SpecifierContext *sp) { /* Parses one item from the format specifier in ctx and put the info into sp. If we are done with * this specifier returns true, otherwise this function should be called again. */ /* This implementation assumes 32-bit ints. Also note that all types smaller than int are promoted to * int in vararg functions, which is why we fetch only ints for any such types. The compiler would * otherwise warn about fetching smaller types. */ assert_cc(sizeof(int) == 4); assert_cc(sizeof(wchar_t) <= sizeof(int)); assert_cc(sizeof(long long) == sizeof(intmax_t)); assert(ctx); assert(sp); switch (*ctx->format) { case '#': sp->alternative_form = true; return false; case '.': sp->have_field_width = true; return false; case '-': sp->align_left = true; return false; case '+': case ' ': sp->sign_pad = *ctx->format; return false; case '0': if (!sp->have_field_width) { sp->pad_zero = true; return false; } /* If field width has already been provided then 0 is part of precision (%.0s). */ _fallthrough_; case '*': case '1' ... '9': { int64_t i; if (*ctx->format == '*') i = va_arg(ctx->ap, int); else { uint64_t u; if (!parse_number8(ctx->format, &u, &ctx->format) || u > INT_MAX) assert_not_reached(); ctx->format--; /* Point it back to the last digit. */ i = u; } if (sp->have_field_width) { /* Negative precision is ignored. */ if (i >= 0) sp->len = (size_t) i; } else { /* Negative field width is treated as positive field width with '-' flag. */ if (i < 0) { i *= -1; sp->align_left = true; } sp->padded_len = i; } return false; } case 'h': if (*(ctx->format + 1) == 'h') ctx->format++; /* char/short gets promoted to int, nothing to do here. */ return false; case 'l': if (*(ctx->format + 1) == 'l') { ctx->format++; sp->longlong_arg = true; } else sp->long_arg = true; return false; case 'z': sp->long_arg = sizeof(size_t) == sizeof(long); sp->longlong_arg = !sp->long_arg && sizeof(size_t) == sizeof(long long); return false; case 'j': sp->long_arg = sizeof(intmax_t) == sizeof(long); sp->longlong_arg = !sp->long_arg && sizeof(intmax_t) == sizeof(long long); return false; case 't': sp->long_arg = sizeof(ptrdiff_t) == sizeof(long); sp->longlong_arg = !sp->long_arg && sizeof(ptrdiff_t) == sizeof(long long); return false; case '%': sp->str = "%"; sp->len = 1; return push_str(ctx, sp); case 'c': sp->wstr = &(wchar_t){ va_arg(ctx->ap, int) }; sp->len = 1; return push_str(ctx, sp); case 's': if (sp->long_arg) { sp->wstr = va_arg(ctx->ap, const wchar_t *) ?: L"(null)"; sp->len = wcsnlen(sp->wstr, sp->len); } else { sp->str = va_arg(ctx->ap, const char *) ?: "(null)"; sp->len = strnlen8(sp->str, sp->len); } return push_str(ctx, sp); case 'd': case 'i': case 'u': case 'x': case 'X': sp->lowercase = *ctx->format == 'x'; sp->is_signed = IN_SET(*ctx->format, 'd', 'i'); sp->base = IN_SET(*ctx->format, 'x', 'X') ? 16 : 10; if (sp->len == SIZE_MAX) sp->len = 1; uint64_t v; if (sp->longlong_arg) v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long long) : va_arg(ctx->ap, unsigned long long); else if (sp->long_arg) v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long) : va_arg(ctx->ap, unsigned long); else v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, int) : va_arg(ctx->ap, unsigned); return push_num(ctx, sp, v); case 'p': { const void *ptr = va_arg(ctx->ap, const void *); if (!ptr) { sp->str = NULLSTR; sp->len = STRLEN(NULLSTR); return push_str(ctx, sp); } sp->base = 16; sp->lowercase = true; sp->alternative_form = true; sp->len = 0; /* Precision is ignored for %p. */ return push_num(ctx, sp, (uintptr_t) ptr); } case 'm': { sp->str = status_to_string(ctx->status); if (sp->str) { sp->len = strlen8(sp->str); return push_str(ctx, sp); } sp->base = 16; sp->lowercase = true; sp->alternative_form = true; sp->len = 0; return push_num(ctx, sp, ctx->status); } default: assert_not_reached(); } } /* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts. * * Supported: * - Flags: #, 0, +, -, space * - Lengths: h, hh, l, ll, z, j, t * - Specifiers: %, c, s, u, i, d, x, X, p, m * - Precision and width (inline or as int arg using *) * * Notable differences: * - Passing NULL to %s is permitted and will print "(null)" * - %p will also use "(null)" * - The provided EFI_STATUS is used for %m instead of errno * - "\n" is translated to "\r\n" */ _printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *format, va_list ap, bool ret) { assert(format); FormatContext ctx = { .buf = ctx.stack_buf, .n_buf = ELEMENTSOF(ctx.stack_buf), .format = format, .status = status, }; /* We cannot put this into the struct without making a copy. */ va_copy(ctx.ap, ap); while (*ctx.format != '\0') { SpecifierContext sp = { .len = SIZE_MAX }; switch (*ctx.format) { case '%': ctx.format++; while (!handle_format_specifier(&ctx, &sp)) ctx.format++; ctx.format++; break; case '\n': ctx.format++; sp.str = "\r\n"; sp.len = 2; push_str(&ctx, &sp); break; default: sp.str = ctx.format++; while (!IN_SET(*ctx.format, '%', '\n', '\0')) ctx.format++; sp.len = ctx.format - sp.str; push_str(&ctx, &sp); } } va_end(ctx.ap); assert(ctx.n < ctx.n_buf); ctx.buf[ctx.n++] = '\0'; if (ret) { if (ctx.dyn_buf) return TAKE_PTR(ctx.dyn_buf); char16_t *ret_buf = xnew(char16_t, ctx.n); memcpy(ret_buf, ctx.buf, ctx.n * sizeof(*ctx.buf)); return ret_buf; } ST->ConOut->OutputString(ST->ConOut, ctx.buf); return mfree(ctx.dyn_buf); } void printf_status(EFI_STATUS status, const char *format, ...) { va_list ap; va_start(ap, format); printf_internal(status, format, ap, false); va_end(ap); } void vprintf_status(EFI_STATUS status, const char *format, va_list ap) { printf_internal(status, format, ap, false); } char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...) { va_list ap; va_start(ap, format); char16_t *ret = printf_internal(status, format, ap, true); va_end(ap); return ret; } char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) { return printf_internal(status, format, ap, true); } /* To provide the actual implementation for these we need to remove the redirection to the builtins. */ # undef memchr # undef memcmp # undef memcpy # undef memset _used_ void *memchr(const void *p, int c, size_t n); _used_ int memcmp(const void *p1, const void *p2, size_t n); _used_ void *memcpy(void * restrict dest, const void * restrict src, size_t n); _used_ void *memset(void *p, int c, size_t n); void *memchr(const void *p, int c, size_t n) { if (!p || n == 0) return NULL; const uint8_t *q = p; for (size_t i = 0; i < n; i++) if (q[i] == (unsigned char) c) return (void *) (q + i); return NULL; } int memcmp(const void *p1, const void *p2, size_t n) { const uint8_t *up1 = p1, *up2 = p2; int r; if (!p1 || !p2) return CMP(p1, p2); while (n > 0) { r = CMP(*up1, *up2); if (r != 0) return r; up1++; up2++; n--; } return 0; } void *memcpy(void * restrict dest, const void * restrict src, size_t n) { if (!dest || !src || n == 0) return dest; /* The firmware-provided memcpy is likely optimized, so use that. The function is guaranteed to be * available by the UEFI spec. We still make it depend on the boot services pointer being set just in * case the compiler emits a call before it is available. */ if (_likely_(BS)) { BS->CopyMem(dest, (void *) src, n); return dest; } uint8_t *d = dest; const uint8_t *s = src; while (n > 0) { *d = *s; d++; s++; n--; } return dest; } void *memset(void *p, int c, size_t n) { if (!p || n == 0) return p; /* See comment in efi_memcpy. Note that the signature has c and n swapped! */ if (_likely_(BS)) { BS->SetMem(p, n, c); return p; } uint8_t *q = p; while (n > 0) { *q = c; q++; n--; } return p; } size_t strspn16(const char16_t *p, const char16_t *good) { assert(p); assert(good); const char16_t *i = p; for (; *i != 0; i++) if (!strchr16(good, *i)) break; return i - p; } size_t strcspn16(const char16_t *p, const char16_t *bad) { assert(p); assert(bad); const char16_t *i = p; for (; *i != 0; i++) if (strchr16(bad, *i)) break; return i - p; } ubustub-1/elf2efi.py000077500000000000000000000576711504315023600146150ustar00rootroot00000000000000#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later # Convert ELF static PIE to PE/EFI image. # To do so we simply copy desired ELF sections while preserving their memory layout to ensure that # code still runs as expected. We then translate ELF relocations to PE relocations so that the EFI # loader/firmware can properly load the binary to any address at runtime. # # To make this as painless as possible we only operate on static PIEs as they should only contain # base relocations that are easy to handle as they have a one-to-one mapping to PE relocations. # # EDK2 does a similar process using their GenFw tool. The main difference is that they use the # --emit-relocs linker flag, which emits a lot of different (static) ELF relocation types that have # to be handled differently for each architecture and is overall more work than its worth. # # Note that on arches where binutils has PE support (x86/x86_64 mostly, aarch64 only recently) # objcopy can be used to convert ELF to PE. But this will still not convert ELF relocations, making # the resulting binary useless. gnu-efi relies on this method and contains a stub that performs the # ELF dynamic relocations at runtime. # pylint: disable=attribute-defined-outside-init import argparse import hashlib import io import os import pathlib import sys import time import typing from ctypes import ( c_char, c_uint8, c_uint16, c_uint32, c_uint64, LittleEndianStructure, sizeof, ) from elftools.elf.constants import SH_FLAGS from elftools.elf.elffile import ELFFile from elftools.elf.enums import ( ENUM_DT_FLAGS_1, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64, ) from elftools.elf.relocation import ( Relocation as ElfRelocation, RelocationTable as ElfRelocationTable, ) class PeCoffHeader(LittleEndianStructure): _fields_ = ( ("Machine", c_uint16), ("NumberOfSections", c_uint16), ("TimeDateStamp", c_uint32), ("PointerToSymbolTable", c_uint32), ("NumberOfSymbols", c_uint32), ("SizeOfOptionalHeader", c_uint16), ("Characteristics", c_uint16), ) class PeDataDirectory(LittleEndianStructure): _fields_ = ( ("VirtualAddress", c_uint32), ("Size", c_uint32), ) class PeRelocationBlock(LittleEndianStructure): _fields_ = ( ("PageRVA", c_uint32), ("BlockSize", c_uint32), ) def __init__(self, PageRVA: int): super().__init__(PageRVA) self.entries: typing.List[PeRelocationEntry] = [] class PeRelocationEntry(LittleEndianStructure): _fields_ = ( ("Offset", c_uint16, 12), ("Type", c_uint16, 4), ) class PeOptionalHeaderStart(LittleEndianStructure): _fields_ = ( ("Magic", c_uint16), ("MajorLinkerVersion", c_uint8), ("MinorLinkerVersion", c_uint8), ("SizeOfCode", c_uint32), ("SizeOfInitializedData", c_uint32), ("SizeOfUninitializedData", c_uint32), ("AddressOfEntryPoint", c_uint32), ("BaseOfCode", c_uint32), ) class PeOptionalHeaderMiddle(LittleEndianStructure): _fields_ = ( ("SectionAlignment", c_uint32), ("FileAlignment", c_uint32), ("MajorOperatingSystemVersion", c_uint16), ("MinorOperatingSystemVersion", c_uint16), ("MajorImageVersion", c_uint16), ("MinorImageVersion", c_uint16), ("MajorSubsystemVersion", c_uint16), ("MinorSubsystemVersion", c_uint16), ("Win32VersionValue", c_uint32), ("SizeOfImage", c_uint32), ("SizeOfHeaders", c_uint32), ("CheckSum", c_uint32), ("Subsystem", c_uint16), ("DllCharacteristics", c_uint16), ) class PeOptionalHeaderEnd(LittleEndianStructure): _fields_ = ( ("LoaderFlags", c_uint32), ("NumberOfRvaAndSizes", c_uint32), ("ExportTable", PeDataDirectory), ("ImportTable", PeDataDirectory), ("ResourceTable", PeDataDirectory), ("ExceptionTable", PeDataDirectory), ("CertificateTable", PeDataDirectory), ("BaseRelocationTable", PeDataDirectory), ("Debug", PeDataDirectory), ("Architecture", PeDataDirectory), ("GlobalPtr", PeDataDirectory), ("TLSTable", PeDataDirectory), ("LoadConfigTable", PeDataDirectory), ("BoundImport", PeDataDirectory), ("IAT", PeDataDirectory), ("DelayImportDescriptor", PeDataDirectory), ("CLRRuntimeHeader", PeDataDirectory), ("Reserved", PeDataDirectory), ) class PeOptionalHeader(LittleEndianStructure): pass class PeOptionalHeader32(PeOptionalHeader): _anonymous_ = ("Start", "Middle", "End") _fields_ = ( ("Start", PeOptionalHeaderStart), ("BaseOfData", c_uint32), ("ImageBase", c_uint32), ("Middle", PeOptionalHeaderMiddle), ("SizeOfStackReserve", c_uint32), ("SizeOfStackCommit", c_uint32), ("SizeOfHeapReserve", c_uint32), ("SizeOfHeapCommit", c_uint32), ("End", PeOptionalHeaderEnd), ) class PeOptionalHeader32Plus(PeOptionalHeader): _anonymous_ = ("Start", "Middle", "End") _fields_ = ( ("Start", PeOptionalHeaderStart), ("ImageBase", c_uint64), ("Middle", PeOptionalHeaderMiddle), ("SizeOfStackReserve", c_uint64), ("SizeOfStackCommit", c_uint64), ("SizeOfHeapReserve", c_uint64), ("SizeOfHeapCommit", c_uint64), ("End", PeOptionalHeaderEnd), ) class PeSection(LittleEndianStructure): _fields_ = ( ("Name", c_char * 8), ("VirtualSize", c_uint32), ("VirtualAddress", c_uint32), ("SizeOfRawData", c_uint32), ("PointerToRawData", c_uint32), ("PointerToRelocations", c_uint32), ("PointerToLinenumbers", c_uint32), ("NumberOfRelocations", c_uint16), ("NumberOfLinenumbers", c_uint16), ("Characteristics", c_uint32), ) def __init__(self): super().__init__() self.data = bytearray() N_DATA_DIRECTORY_ENTRIES = 16 assert sizeof(PeSection) == 40 assert sizeof(PeCoffHeader) == 20 assert sizeof(PeOptionalHeader32) == 224 assert sizeof(PeOptionalHeader32Plus) == 240 PE_CHARACTERISTICS_RX = 0x60000020 # CNT_CODE|MEM_READ|MEM_EXECUTE PE_CHARACTERISTICS_RW = 0xC0000040 # CNT_INITIALIZED_DATA|MEM_READ|MEM_WRITE PE_CHARACTERISTICS_R = 0x40000040 # CNT_INITIALIZED_DATA|MEM_READ IGNORE_SECTIONS = [ ".eh_frame", ".eh_frame_hdr", ".ARM.exidx", ".relro_padding", ] IGNORE_SECTION_TYPES = [ "SHT_DYNAMIC", "SHT_DYNSYM", "SHT_GNU_ATTRIBUTES", "SHT_GNU_HASH", "SHT_HASH", "SHT_NOTE", "SHT_REL", "SHT_RELA", "SHT_RELR", "SHT_STRTAB", "SHT_SYMTAB", ] # EFI mandates 4KiB memory pages. SECTION_ALIGNMENT = 4096 FILE_ALIGNMENT = 512 # Nobody cares about DOS headers, so put the PE header right after. PE_OFFSET = 64 PE_MAGIC = b"PE\0\0" def align_to(x: int, align: int) -> int: return (x + align - 1) & ~(align - 1) def align_down(x: int, align: int) -> int: return x & ~(align - 1) def next_section_address(sections: typing.List[PeSection]) -> int: return align_to(sections[-1].VirtualAddress + sections[-1].VirtualSize, SECTION_ALIGNMENT) class BadSectionError(ValueError): "One of the sections is in a bad state" def iter_copy_sections(elf: ELFFile) -> typing.Iterator[PeSection]: pe_s = None # This is essentially the same as copying by ELF load segments, except that we assemble them # manually, so that we can easily strip unwanted sections. We try to only discard things we know # about so that there are no surprises. relro = None for elf_seg in elf.iter_segments(): if elf_seg["p_type"] == "PT_LOAD" and elf_seg["p_align"] != SECTION_ALIGNMENT: raise BadSectionError(f"ELF segment {elf_seg['p_type']} is not properly aligned" f" ({elf_seg['p_align']} != {SECTION_ALIGNMENT})") if elf_seg["p_type"] == "PT_GNU_RELRO": relro = elf_seg for elf_s in elf.iter_sections(): if ( elf_s["sh_flags"] & SH_FLAGS.SHF_ALLOC == 0 or elf_s["sh_type"] in IGNORE_SECTION_TYPES or elf_s.name in IGNORE_SECTIONS or elf_s["sh_size"] == 0 ): continue if elf_s["sh_type"] not in ["SHT_PROGBITS", "SHT_NOBITS"]: raise BadSectionError(f"Unknown section {elf_s.name} with type {elf_s['sh_type']}") if elf_s.name == '.got': # FIXME: figure out why those sections are inserted print("WARNING: Non-empty .got section", file=sys.stderr) if elf_s["sh_flags"] & SH_FLAGS.SHF_EXECINSTR: rwx = PE_CHARACTERISTICS_RX elif elf_s["sh_flags"] & SH_FLAGS.SHF_WRITE: rwx = PE_CHARACTERISTICS_RW else: rwx = PE_CHARACTERISTICS_R # PE images are always relro. if relro and relro.section_in_segment(elf_s): rwx = PE_CHARACTERISTICS_R if pe_s and pe_s.Characteristics != rwx: yield pe_s pe_s = None if pe_s: # Insert padding to properly align the section. pad_len = elf_s["sh_addr"] - pe_s.VirtualAddress - len(pe_s.data) pe_s.data += bytearray(pad_len) + elf_s.data() else: pe_s = PeSection() pe_s.VirtualAddress = elf_s["sh_addr"] pe_s.Characteristics = rwx pe_s.data = elf_s.data() if pe_s: yield pe_s def convert_sections(elf: ELFFile, opt: PeOptionalHeader) -> typing.List[PeSection]: last_vma = (0, 0) sections = [] for pe_s in iter_copy_sections(elf): # Truncate the VMA to the nearest page and insert appropriate padding. This should not # cause any overlap as this is pretty much how ELF *segments* are loaded/mmapped anyways. # The ELF sections inside should also be properly aligned as we reuse the ELF VMA layout # for the PE image. vma = pe_s.VirtualAddress pe_s.VirtualAddress = align_down(vma, SECTION_ALIGNMENT) pe_s.data = bytearray(vma - pe_s.VirtualAddress) + pe_s.data pe_s.VirtualSize = len(pe_s.data) pe_s.SizeOfRawData = align_to(len(pe_s.data), FILE_ALIGNMENT) pe_s.Name = { PE_CHARACTERISTICS_RX: b".text", PE_CHARACTERISTICS_RW: b".data", PE_CHARACTERISTICS_R: b".rodata", }[pe_s.Characteristics] # This can happen if not building with '-z separate-code'. if pe_s.VirtualAddress < sum(last_vma): raise BadSectionError(f"Section {pe_s.Name.decode()!r} @0x{pe_s.VirtualAddress:x} overlaps" f" previous section @0x{last_vma[0]:x}+0x{last_vma[1]:x}=@0x{sum(last_vma):x}") last_vma = (pe_s.VirtualAddress, pe_s.VirtualSize) if pe_s.Name == b".text": opt.BaseOfCode = pe_s.VirtualAddress opt.SizeOfCode += pe_s.VirtualSize else: opt.SizeOfInitializedData += pe_s.VirtualSize if pe_s.Name == b".data" and isinstance(opt, PeOptionalHeader32): opt.BaseOfData = pe_s.VirtualAddress sections.append(pe_s) return sections def copy_sections( elf: ELFFile, opt: PeOptionalHeader, input_names: str, sections: typing.List[PeSection], ): for name in input_names.split(","): elf_s = elf.get_section_by_name(name) if not elf_s: continue if elf_s.data_alignment > 1 and SECTION_ALIGNMENT % elf_s.data_alignment != 0: raise BadSectionError(f"ELF section {name} is not aligned") if elf_s["sh_flags"] & (SH_FLAGS.SHF_EXECINSTR | SH_FLAGS.SHF_WRITE) != 0: raise BadSectionError(f"ELF section {name} is not read-only data") pe_s = PeSection() pe_s.Name = name.encode() pe_s.data = elf_s.data() pe_s.VirtualAddress = next_section_address(sections) pe_s.VirtualSize = len(elf_s.data()) pe_s.SizeOfRawData = align_to(len(elf_s.data()), FILE_ALIGNMENT) pe_s.Characteristics = PE_CHARACTERISTICS_R opt.SizeOfInitializedData += pe_s.VirtualSize sections.append(pe_s) def apply_elf_relative_relocation( reloc: ElfRelocation, image_base: int, sections: typing.List[PeSection], addend_size: int, ): [target] = [pe_s for pe_s in sections if pe_s.VirtualAddress <= reloc["r_offset"] < pe_s.VirtualAddress + len(pe_s.data)] addend_offset = reloc["r_offset"] - target.VirtualAddress if reloc.is_RELA(): addend = reloc["r_addend"] else: addend = target.data[addend_offset : addend_offset + addend_size] addend = int.from_bytes(addend, byteorder="little") value = (image_base + addend).to_bytes(addend_size, byteorder="little") target.data[addend_offset : addend_offset + addend_size] = value def convert_elf_reloc_table( elf: ELFFile, elf_reloc_table: ElfRelocationTable, elf_image_base: int, sections: typing.List[PeSection], pe_reloc_blocks: typing.Dict[int, PeRelocationBlock], ): NONE_RELOC = { "EM_386": ENUM_RELOC_TYPE_i386["R_386_NONE"], "EM_AARCH64": ENUM_RELOC_TYPE_AARCH64["R_AARCH64_NONE"], "EM_ARM": ENUM_RELOC_TYPE_ARM["R_ARM_NONE"], "EM_LOONGARCH": 0, "EM_RISCV": 0, "EM_X86_64": ENUM_RELOC_TYPE_x64["R_X86_64_NONE"], }[elf["e_machine"]] RELATIVE_RELOC = { "EM_386": ENUM_RELOC_TYPE_i386["R_386_RELATIVE"], "EM_AARCH64": ENUM_RELOC_TYPE_AARCH64["R_AARCH64_RELATIVE"], "EM_ARM": ENUM_RELOC_TYPE_ARM["R_ARM_RELATIVE"], "EM_LOONGARCH": 3, "EM_RISCV": 3, "EM_X86_64": ENUM_RELOC_TYPE_x64["R_X86_64_RELATIVE"], }[elf["e_machine"]] for reloc in elf_reloc_table.iter_relocations(): if reloc["r_info_type"] == NONE_RELOC: continue if reloc["r_info_type"] == RELATIVE_RELOC: apply_elf_relative_relocation(reloc, elf_image_base, sections, elf.elfclass // 8) # Now that the ELF relocation has been applied, we can create a PE relocation. block_rva = reloc["r_offset"] & ~0xFFF if block_rva not in pe_reloc_blocks: pe_reloc_blocks[block_rva] = PeRelocationBlock(block_rva) entry = PeRelocationEntry() entry.Offset = reloc["r_offset"] & 0xFFF # REL_BASED_HIGHLOW or REL_BASED_DIR64 entry.Type = 3 if elf.elfclass == 32 else 10 pe_reloc_blocks[block_rva].entries.append(entry) continue raise BadSectionError(f"Unsupported relocation {reloc}") def convert_elf_relocations( elf: ELFFile, opt: PeOptionalHeader, sections: typing.List[PeSection], minimum_sections: int, ) -> typing.Optional[PeSection]: dynamic = elf.get_section_by_name(".dynamic") if dynamic is None: raise BadSectionError("ELF .dynamic section is missing") [flags_tag] = dynamic.iter_tags("DT_FLAGS_1") if not flags_tag["d_val"] & ENUM_DT_FLAGS_1["DF_1_PIE"]: raise ValueError("ELF file is not a PIE") # This checks that the ELF image base is 0. symtab = elf.get_section_by_name(".symtab") if symtab: exe_start = symtab.get_symbol_by_name("__executable_start") if exe_start and exe_start[0]["st_value"] != 0: raise ValueError("Unexpected ELF image base") opt.SizeOfHeaders = align_to(PE_OFFSET + len(PE_MAGIC) + sizeof(PeCoffHeader) + sizeof(opt) + sizeof(PeSection) * max(len(sections) + 1, minimum_sections), FILE_ALIGNMENT) # We use the basic VMA layout from the ELF image in the PE image. This could cause the first # section to overlap the PE image headers during runtime at VMA 0. We can simply apply a fixed # offset relative to the PE image base when applying/converting ELF relocations. Afterwards we # just have to apply the offset to the PE addresses so that the PE relocations work correctly on # the ELF portions of the image. segment_offset = 0 if sections[0].VirtualAddress < opt.SizeOfHeaders: segment_offset = align_to(opt.SizeOfHeaders - sections[0].VirtualAddress, SECTION_ALIGNMENT) opt.AddressOfEntryPoint = elf["e_entry"] + segment_offset opt.BaseOfCode += segment_offset if isinstance(opt, PeOptionalHeader32): opt.BaseOfData += segment_offset pe_reloc_blocks: typing.Dict[int, PeRelocationBlock] = {} for reloc_type, reloc_table in dynamic.get_relocation_tables().items(): if reloc_type not in ["REL", "RELA"]: raise BadSectionError(f"Unsupported relocation type {reloc_type}") convert_elf_reloc_table(elf, reloc_table, opt.ImageBase + segment_offset, sections, pe_reloc_blocks) for pe_s in sections: pe_s.VirtualAddress += segment_offset if len(pe_reloc_blocks) == 0: return None data = bytearray() for rva in sorted(pe_reloc_blocks): block = pe_reloc_blocks[rva] n_relocs = len(block.entries) # Each block must start on a 32-bit boundary. Because each entry is 16 bits # the len has to be even. We pad by adding a none relocation. if n_relocs % 2 != 0: n_relocs += 1 block.entries.append(PeRelocationEntry()) block.PageRVA += segment_offset block.BlockSize = sizeof(PeRelocationBlock) + sizeof(PeRelocationEntry) * n_relocs data += block for entry in sorted(block.entries, key=lambda e: e.Offset): data += entry pe_reloc_s = PeSection() pe_reloc_s.Name = b".reloc" pe_reloc_s.data = data pe_reloc_s.VirtualAddress = next_section_address(sections) pe_reloc_s.VirtualSize = len(data) pe_reloc_s.SizeOfRawData = align_to(len(data), FILE_ALIGNMENT) # CNT_INITIALIZED_DATA|MEM_READ|MEM_DISCARDABLE pe_reloc_s.Characteristics = 0x42000040 sections.append(pe_reloc_s) opt.SizeOfInitializedData += pe_reloc_s.VirtualSize return pe_reloc_s def write_pe( file, coff: PeCoffHeader, opt: PeOptionalHeader, sections: typing.List[PeSection], ): file.write(b"MZ") file.seek(0x3C, io.SEEK_SET) file.write(PE_OFFSET.to_bytes(2, byteorder="little")) file.seek(PE_OFFSET, io.SEEK_SET) file.write(PE_MAGIC) file.write(coff) file.write(opt) offset = opt.SizeOfHeaders for pe_s in sorted(sections, key=lambda s: s.VirtualAddress): if pe_s.VirtualAddress < opt.SizeOfHeaders: raise BadSectionError(f"Section {pe_s.Name} @0x{pe_s.VirtualAddress:x} overlaps" " PE headers ending at 0x{opt.SizeOfHeaders:x}") pe_s.PointerToRawData = offset file.write(pe_s) offset = align_to(offset + len(pe_s.data), FILE_ALIGNMENT) assert file.tell() <= opt.SizeOfHeaders for pe_s in sections: file.seek(pe_s.PointerToRawData, io.SEEK_SET) file.write(pe_s.data) file.truncate(offset) def elf2efi(args: argparse.Namespace): elf = ELFFile(args.ELF) if not elf.little_endian: raise ValueError("ELF file is not little-endian") if elf["e_type"] not in ["ET_DYN", "ET_EXEC"]: raise ValueError(f"Unsupported ELF type {elf['e_type']}") pe_arch = { "EM_386": 0x014C, "EM_AARCH64": 0xAA64, "EM_ARM": 0x01C2, "EM_LOONGARCH": 0x6232 if elf.elfclass == 32 else 0x6264, "EM_RISCV": 0x5032 if elf.elfclass == 32 else 0x5064, "EM_X86_64": 0x8664, }.get(elf["e_machine"]) if pe_arch is None: raise ValueError(f"Unsupported ELF architecture {elf['e_machine']}") coff = PeCoffHeader() opt = PeOptionalHeader32() if elf.elfclass == 32 else PeOptionalHeader32Plus() # We relocate to a unique image base to reduce the chances for runtime relocation to occur. base_name = pathlib.Path(args.PE.name).name.encode() opt.ImageBase = int(hashlib.sha1(base_name).hexdigest()[0:8], 16) if elf.elfclass == 32: opt.ImageBase = (0x400000 + opt.ImageBase) & 0xFFFF0000 else: opt.ImageBase = (0x100000000 + opt.ImageBase) & 0x1FFFF0000 sections = convert_sections(elf, opt) copy_sections(elf, opt, args.copy_sections, sections) pe_reloc_s = convert_elf_relocations(elf, opt, sections, args.minimum_sections) coff.Machine = pe_arch coff.NumberOfSections = len(sections) coff.TimeDateStamp = int(os.environ.get("SOURCE_DATE_EPOCH") or time.time()) coff.SizeOfOptionalHeader = sizeof(opt) # EXECUTABLE_IMAGE|LINE_NUMS_STRIPPED|LOCAL_SYMS_STRIPPED|DEBUG_STRIPPED # and (32BIT_MACHINE or LARGE_ADDRESS_AWARE) coff.Characteristics = 0x30E if elf.elfclass == 32 else 0x22E opt.SectionAlignment = SECTION_ALIGNMENT opt.FileAlignment = FILE_ALIGNMENT opt.MajorImageVersion = args.version_major opt.MinorImageVersion = args.version_minor opt.MajorSubsystemVersion = args.efi_major opt.MinorSubsystemVersion = args.efi_minor opt.Subsystem = args.subsystem opt.Magic = 0x10B if elf.elfclass == 32 else 0x20B opt.SizeOfImage = next_section_address(sections) # DYNAMIC_BASE|NX_COMPAT|HIGH_ENTROPY_VA or DYNAMIC_BASE|NX_COMPAT opt.DllCharacteristics = 0x160 if elf.elfclass == 64 else 0x140 # These values are taken from a natively built PE binary (although, unused by EDK2/EFI). opt.SizeOfStackReserve = 0x100000 opt.SizeOfStackCommit = 0x001000 opt.SizeOfHeapReserve = 0x100000 opt.SizeOfHeapCommit = 0x001000 opt.NumberOfRvaAndSizes = N_DATA_DIRECTORY_ENTRIES if pe_reloc_s: opt.BaseRelocationTable = PeDataDirectory( pe_reloc_s.VirtualAddress, pe_reloc_s.VirtualSize ) write_pe(args.PE, coff, opt, sections) def create_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Convert ELF binaries to PE/EFI") parser.add_argument( "--version-major", type=int, default=0, help="Major image version of EFI image", ) parser.add_argument( "--version-minor", type=int, default=0, help="Minor image version of EFI image", ) parser.add_argument( "--efi-major", type=int, default=0, help="Minimum major EFI subsystem version", ) parser.add_argument( "--efi-minor", type=int, default=0, help="Minimum minor EFI subsystem version", ) parser.add_argument( "--subsystem", type=int, default=10, help="PE subsystem", ) parser.add_argument( "ELF", type=argparse.FileType("rb"), help="Input ELF file", ) parser.add_argument( "PE", type=argparse.FileType("wb"), help="Output PE/EFI file", ) parser.add_argument( "--minimum-sections", type=int, default=0, help="Minimum number of sections to leave space for", ) parser.add_argument( "--copy-sections", type=str, default="", help="Copy these sections if found", ) return parser def main(): parser = create_parser() elf2efi(parser.parse_args()) if __name__ == "__main__": main() ubustub-1/export-vars.c000066400000000000000000000057411504315023600153510ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-path-util.h" #include "efi-efivars.h" #include "export-vars.h" #include "part-discovery.h" #include "url-discovery.h" #include "util.h" void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) { assert(loaded_image); /* Export the device path this image is started from, if it's not set yet */ if (loaded_image->DeviceHandle) { if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", /* ret_data= */ NULL, /* ret_size= */ NULL) != EFI_SUCCESS) { _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle); if (uuid) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0); } if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDeviceURL", /* ret_data= */ NULL, /* ret_size= */ NULL) != EFI_SUCCESS) { _cleanup_free_ char16_t *url = disk_get_url(loaded_image->DeviceHandle); if (url) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderDeviceURL", url, 0); } } /* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the * UEFI firmware without any boot loader, and hence set the LoaderImageIdentifier ourselves. Note * that some boot chain loaders neither set LoaderImageIdentifier nor make FilePath available to us, * in which case there's simple nothing to set for us. (The UEFI spec doesn't really say who's wrong * here, i.e. whether FilePath may be NULL or not, hence handle this gracefully and check if FilePath * is non-NULL explicitly.) */ if (loaded_image->FilePath && efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS) { _cleanup_free_ char16_t *s = NULL; if (device_path_to_str(loaded_image->FilePath, &s) == EFI_SUCCESS) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", s, 0); } /* if LoaderFirmwareInfo is not set, let's set it */ if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) { _cleanup_free_ char16_t *s = NULL; s = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", s, 0); } /* ditto for LoaderFirmwareType */ if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) { _cleanup_free_ char16_t *s = NULL; s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", s, 0); } } ubustub-1/hwids/000077500000000000000000000000001504315023600140225ustar00rootroot00000000000000ubustub-1/hwids/hwid2json.py000077500000000000000000000033361504315023600163130ustar00rootroot00000000000000#!/usr/bin/python3 # SPDX-License-Identifier: 0BSD from uuid import UUID from pathlib import Path from typing import * import re import json import sys guid_regexp = re.compile(r'\{[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}\}', re.I) def parse_hwid_file(hwid_file: Path, inpath: Path, outpath: Path) -> None: content = hwid_file.open().readlines() data: dict[str, str] = { 'Manufacturer': '', 'Family': '', 'Compatible': 'FIXME!', } guids: list[UUID] = [] for line in content: for k in data: if line.startswith(k): data[k] = line.split(':')[1].strip() break else: guid = guid_regexp.match(line) if guid is not None: guids.append(UUID(guid.group(0)[1:-1])) for k, v in data.items(): if not v: raise ValueError(f'hwid description file "{hwid_file}" does not contain "{k}"') name = data['Manufacturer'] + ' ' + data['Family'] compatible = data['Compatible'] device = { 'type': 'devicetree', 'name': name, 'compatible': compatible, 'hwids': guids, } with open(str(outpath / hwid_file.relative_to(inpath).with_suffix('.json')), 'w', encoding='utf-8') as f: json.dump(device, f, ensure_ascii=False, indent=4, default=str) def parse_hwid_dir(inpath: Path, outpath: Path) -> None: hwid_files = inpath.rglob('*.txt') for hwid_file in hwid_files: parse_hwid_file(hwid_file, inpath, outpath) inpath = Path('./txt') outpath = Path('./json') if len(sys.argv) > 1: inpath = Path(sys.argv[1]) if len(sys.argv) > 2: outpath = Path(sys.argv[2]) parse_hwid_dir(inpath, outpath) ubustub-1/hwids/json/000077500000000000000000000000001504315023600147735ustar00rootroot00000000000000ubustub-1/hwids/json/msm8998-lenovo-miix-630-81f1.json000066400000000000000000000015061504315023600222550ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO Miix 630", "compatible": "lenovo,miix-630", "hwids": [ "16a55446-eba9-5f97-80e3-5e39d8209bc3", "c4c9a6be-5383-5de7-af35-c2de505edec8", "14f581d2-d059-5cb2-9f8b-56d8be7932c9", "a51054fb-5eef-594a-a5a0-cd87632d0aea", "307ab358-ed84-57fe-bf05-e9195a28198d", "7e613574-5445-5797-9567-2d0ed86e6ffa", "b0f4463c-f851-5ec3-b031-2ccb873a609a", "08b75d1f-6643-52a1-9bdd-071052860b33", "dacf4a59-8e87-55c5-8b93-6912ded6bf7f", "d0a8deb1-4cb5-50cd-bdda-595cfc13230c", "71d86d4d-02f8-5566-a7a1-529cef184b7e", "6de5d951-d755-576b-bd09-c5cf66b27234", "34df58d6-b605-50aa-9313-9b34f5c4b6fc", "e0a96696-f0a6-5466-a6db-207fbe8bae3c", "99431f53-09a1-5869-be79-65e2fa3f341d" ] } ubustub-1/hwids/json/sc7180-acer-aspire1.json000066400000000000000000000015011504315023600210620ustar00rootroot00000000000000{ "type": "devicetree", "name": "Acer Aspire 1", "compatible": "acer,aspire1", "hwids": [ "45d37dbe-40fb-57bd-a257-55f422d4dc0a", "373bfde5-ffaa-504c-84f3-f8f5357dfc29", "e12521bf-0ed8-5406-af87-adad812c57c5", "faa12ed4-bd49-5471-8f74-75c2267c3b46", "965e3681-de3b-5e39-bb62-7d4917d7e36f", "82fe1869-361c-56b2-b853-631747e64aa7", "7e15f49e-04b4-5d56-a567-e7a15ba2aca1", "7c107a7f-2d77-51aa-aef8-8d777e26ffbc", "68b38fff-aadc-512c-937b-99d9c13eb484", "260192d4-06d4-5124-ab46-ba210f4c14d7", "175f000b-3d05-5c01-aedd-817b1a141f93", "24277a94-7064-500f-9854-5264f20cfa99", "92dcc94d-48f7-5ee8-b9ec-a6393fb7a484", "d234a917-df0b-5453-a3d9-f27c06307395", "1e301734-5d49-5df4-9ed2-aa1c0a9dddda" ] } ubustub-1/hwids/json/sc8180x-lenovo-flex-5g-81xe.json000066400000000000000000000015151504315023600223360ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO Yoga 5G 14Q8CX05", "compatible": "lenovo,flex-5g", "hwids": [ "ea646c11-3da1-5c8d-9346-8ff156746650", "5100eeed-c5e2-5b74-9c24-a22ca0644826", "ddb3bcda-db7b-579d-9dd9-bcc4f5b052b8", "fb364c09-efc0-5d16-ac97-0a3e6235b16c", "7e7007ac-603c-55ef-bb77-3548784b9578", "566b9ae8-a7fd-5c44-94d6-bac3e4cf38a7", "6f3bdfb7-f832-5c5f-9777-9e3db35e22a6", "c4ea686c-c56c-5e8e-a91e-89056683d417", "a1a13249-2689-5c6d-a43f-98af040284c4", "01439aea-e75c-5fbb-8842-18dcd1a7b8b3", "65ab9f32-bbc8-52d3-87f9-b618fda7c07e", "41ba2569-88df-57d4-b5e3-350ff985434a", "32b7e294-a252-5a72-b3c6-6197f08c64f1", "71d86d4d-02f8-5566-a7a1-529cef184b7e", "6de5d951-d755-576b-bd09-c5cf66b27234" ] } ubustub-1/hwids/json/sc8180x-lenovo-flex-5g-82ak.json000066400000000000000000000015151504315023600223160ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO Flex 5G 14Q8CX05", "compatible": "lenovo,flex-5g", "hwids": [ "ad47f2e9-2f8c-5cd1-a44e-82f35a43e44e", "997c1c76-5595-5300-9f58-94d2c6ffc586", "b9bf941f-3a32-57da-b609-5fff7fb382cd", "ea658d2b-f644-555d-9b72-e1642401a795", "fb5c3077-39d5-5a44-97ce-2d3be5f6bfec", "16551bd5-37b0-571d-a94c-da61a9cfccf5", "df3ecc56-b61b-5f8e-896f-801a42b536d6", "06675172-9a6e-5276-a505-d205688a87f0", "23dcfb84-d132-5f60-878e-64fe0b9417d6", "12c0e5b0-8886-5444-b42b-93692fa736df", "39fca706-c9a2-54d4-8c7c-d5e292d0a725", "6e266ee4-0ba4-561c-9758-9fd4876af2e2", "32b7e294-a252-5a72-b3c6-6197f08c64f1", "71d86d4d-02f8-5566-a7a1-529cef184b7e", "6de5d951-d755-576b-bd09-c5cf66b27234" ] } ubustub-1/hwids/json/sc8280xp-huawei-gaokun3.json000066400000000000000000000017271504315023600220210ustar00rootroot00000000000000{ "type": "devicetree", "name": "HUAWEI MateBook E", "compatible": "huawei,gaokun3", "hwids": [ "80c86c24-c7a7-5714-abf2-4c48f348cecc", "1c2effc1-1038-584d-ae8b-7c912c8e9504", "6eb75906-3a4e-5de4-94c5-374d8f9723e5", "4f04f31f-17f0-583f-802f-82c3a0b34128", "e1b94e53-0f20-5d01-abfc-cfb348544a31", "b866fc5c-261b-56d8-99e8-03ea0646af8f", "d8846172-f0a0-55ba-bf41-55641f588ea7", "7ea8b73b-2cbb-562b-aecc-7f0f64c42630", "3eb6683b-0153-5365-81c6-cc599783e9c7", "e5a0ed2b-7fed-5e2d-94ed-43dbaf0b9ccc", "0c78ef16-4fe0-5e33-908e-b038949ee608", "8187555f-3681-5463-a0fa-e6b74e49d4c1", "39bed59d-bfe0-5938-9a76-b2f4739af786", "c562b393-1c28-5cc3-a77c-c13c798e5698", "0df4aa3f-2706-51d4-9296-80119e47f1e1", "e98c95a8-b50e-5d8b-b2db-c679a39163df", "13311789-793f-5d95-942c-3b6414a8ad1a", "04798471-7c9b-5189-b99b-4d19e1a6fa89" ] } ubustub-1/hwids/json/sc8280xp-lenovo-thinkpad-x13s-21bx.json000066400000000000000000000015261504315023600236370ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO ThinkPad X13s Gen 1", "compatible": "lenovo,thinkpad-x13s", "hwids": [ "810e34c6-cc69-5e36-8675-2f6e354272d3", "f22c935e-2dc8-5949-9486-09bbf10361b2", "abdbb2cb-ab52-5674-9d0a-2e2cb69bcbb4", "ddf28a3f-43fc-54a4-a6a7-4cba5ad46b3e", "4df470e6-7878-5b0f-b2e0-733d5d9fa228", "3ad863ab-0181-5a2f-9cc1-70eedc446da9", "69c47e1e-fde2-5062-b777-acbeab73784b", "3486eccc-d0ac-534a-9e2f-a1c18bc310c6", "c869f39e-f205-5ca0-be7b-d90f90ef5556", "b470d002-ad8e-5d5c-a7bf-bb1333f2ce4b", "64b71f12-4341-5e5c-b7cd-25b6503799e3", "f249803d-0d95-54f3-a28f-f26c14a03f3b", "e093d715-70f7-51f4-b6c8-b4a7e31def85", "156c9b34-bedb-5bfd-ae1f-ef5d2a994967", "6de5d951-d755-576b-bd09-c5cf66b27234" ] } ubustub-1/hwids/json/sc8280xp-lenovo-thinkpad-x13s-21by.json000066400000000000000000000015261504315023600236400ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO ThinkPad X13s Gen 1", "compatible": "lenovo,thinkpad-x13s", "hwids": [ "b265d777-007e-56e5-b0e2-bd666ab867be", "3f9d2d91-73b2-5316-8c72-a0ecb3f0dae5", "4b189129-8eb2-585c-a1bb-a4cfc979433a", "fbf92a11-bb6f-5adb-b5a7-8abf9acbd7d9", "0909a1c3-3a02-59a0-b1ea-04f1449c104f", "69acf6bf-ed33-5806-857f-c76971d7061e", "ddfbdaa2-7c46-5103-be64-84a9f88c485f", "b41f58ed-7631-561f-9b0c-449a9c293afa", "9f47e28f-e1ee-5cb5-b4ce-8f0605752b3d", "873455fb-b2c5-5c0c-9c2c-90e80d44da57", "a1dfe209-99e5-5ff2-9922-aa4c11491b49", "f249803d-0d95-54f3-a28f-f26c14a03f3b", "e093d715-70f7-51f4-b6c8-b4a7e31def85", "920b6e26-11c6-5beb-8643-fcf5cd74033f", "6de5d951-d755-576b-bd09-c5cf66b27234" ] } ubustub-1/hwids/json/sc8280xp-microsoft-blackrock.json000066400000000000000000000015301504315023600231200ustar00rootroot00000000000000{ "type": "devicetree", "name": "Microsoft Corporation Surface", "compatible": "microsoft,blackrock", "hwids": [ "69ba0503-ca94-5fa3-b78c-5fa21a66c620", "ad2ee931-a048-5253-b350-98c482670765", "5bd24fc5-5edb-51f6-82e6-31a9ef954c5b", "d67e799e-2ba7-555a-a874-a0523a8b3b11", "813677fa-6d11-5756-a44d-dde0f552d3f6", "ce83144b-b123-59e5-8a9a-0c1a13643fc4", "53b87f48-fc47-54e9-ade5-f1a95e885681", "046fefee-341b-5c40-b0a3-1c647d31b500", "f59639f4-4970-5706-9a75-519dd059f69e", "08f06457-aa19-51c5-be4c-0087ce4fa2ed", "11b80238-dbee-57bc-8b26-83c9e5b4057d", "ca2e5189-1d32-509f-88a0-d4ebcc721899", "7ce6d32b-3711-5701-b31a-cc79f61a5719", "2c1da402-8915-572d-a493-c966d32f96cb", "cc0aea32-ad2c-5013-8bed-cede6be8c9f4" ] } ubustub-1/hwids/json/sc8280xp-microsoft-surface-pro-9-5G.json000066400000000000000000000015251504315023600240360ustar00rootroot00000000000000{ "type": "devicetree", "name": "Microsoft Corporation Surface", "compatible": "microsoft,arcata", "hwids": [ "e3d941fa-2bfa-5875-8efd-87ce997f8338", "a659ee2b-502d-50f7-9921-bdbd34734e0b", "5caa88bc-ea9b-5d73-a69a-89024bfff854", "c0cf7078-c325-5cf6-966b-3bbbc155275b", "6309fbb9-68f4-54f9-bbc9-b3ca9685b48c", "9d70dcfd-f56b-58bf-b1bd-a1b8f2b0ec7e", "9bac72c6-83f6-5e21-af8e-bc1f5c2b7cc8", "94fb24a7-ff7a-5d70-9ac8-518a9e44ea64", "009d2337-4f76-514e-b2c1-b2816447b048", "3a486e6f-3b0a-5603-a483-503381d3d8c3", "636b6071-7848-50d5-b0b5-6290c49e9306", "ca2e5189-1d32-509f-88a0-d4ebcc721899", "aca387a9-183e-5da9-8f9d-f460c3f50f54", "7fa0755a-ec45-59cd-a206-bb9a956b030f", "cc0aea32-ad2c-5013-8bed-cede6be8c9f4" ] } ubustub-1/hwids/json/sdm850-lenovo-yoga-c630.json000066400000000000000000000015161504315023600216170ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO YOGA C630-13Q50", "compatible": "lenovo,yoga-c630", "hwids": [ "b8c71349-3669-56f3-99ee-ae473a2edd96", "d17c132e-f06e-5e38-8084-9cd642dd9b34", "8f56cf17-7bdd-5414-832d-97cd26837114", "b323d38a-88c6-5cf6-af0d-0db3f3c2560d", "43b71948-9c47-5372-a5cb-18db47bb873f", "67a23be6-42a6-5900-8325-847a318ce252", "94f73d29-3981-59a8-8f25-214f84d1522a", "5ca3cf2b-d6e9-5b54-93f7-1cebd7b3704f", "81f308c0-db65-50c2-a660-52e06fc0ff9f", "30b031c0-9de7-5d31-a61c-dee772871b7d", "382926c0-ce35-53af-8ff9-ca9cc06cfc7b", "dd3a12ef-e928-519d-83d7-6674a2ae0ffa", "6c95fc34-96cc-5c9f-8e78-6baaffde78ce", "71d86d4d-02f8-5566-a7a1-529cef184b7e", "6de5d951-d755-576b-bd09-c5cf66b27234" ] } ubustub-1/hwids/json/x1e001de-devkit.json000066400000000000000000000010561504315023600204030ustar00rootroot00000000000000{ "type": "devicetree", "name": "Qualcomm SCP_HAMOA", "compatible": "qcom,x1e001de-devkit", "hwids": [ "baa7a649-12d8-56c7-93c5-a4e10f4852be", "c8e75ab8-555c-5952-a3e3-5b607bea031d", "4bb05d50-6c4f-525d-a9ec-8924afd6edea", "830bd4a2-2498-55cf-b561-48f7dc5f4820", "b36a40fa-4640-5b1b-8fa1-6dbde103c80d", "0d601876-0ac6-533e-8386-3a58203d8c33", "f37dc44b-0be4-5a70-86bd-81f3dacff2e9", "9cba20d0-17ad-559f-94cd-cfcbbf5f71f5", "d86bea02-5d71-5ee5-98dc-4f74d5777dde" ] } ubustub-1/hwids/json/x1e78100-lenovo-thinkpad-t14s-21n1.json000066400000000000000000000017521504315023600233400ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO ThinkPad T14s Gen 6", "compatible": "lenovo,thinkpad-t14s-lcd", "hwids": [ "c81fee2f-cf41-5d5a-8c7b-afd6585b1d81", "a9b59fea-e841-508a-a245-3a2d8d2802de", "74593764-b6b9-58e9-bedc-93ebbb1eb057", "e5d83424-0ecb-5632-b7b1-500f04e82725", "76032e78-67a8-5dab-8512-157bfcfb8f75", "dd83478e-e01b-5631-ae74-92ae275a9b4e", "791ecd9d-1547-58e6-b72a-5ce417b729dd", "8c602147-5363-5374-859e-8b7fe2d4d3ce", "498d60ae-9b1d-5b67-8abd-af571babfa94", "acbac5af-aa6a-5690-88f3-e910f04a7ead", "5180bc01-5d18-5870-b955-969da38b2647", "431ff9e9-cd92-51c1-8917-46b0a0ef147c", "e093d715-70f7-51f4-b6c8-b4a7e31def85", "c124cecf-e6dc-5d35-a320-712980cfb68d", "6de5d951-d755-576b-bd09-c5cf66b27234", "19b622ef-27fe-5c2e-bc53-13a79b862c65", "ac09e50f-9b3b-53c0-9752-377c3a0baaa0", "99431f53-09a1-5869-be79-65e2fa3f341d" ] } ubustub-1/hwids/json/x1e78100-lenovo-thinkpad-t14s-21n2.json000066400000000000000000000017521504315023600233410ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO ThinkPad T14s Gen 6", "compatible": "lenovo,thinkpad-t14s-lcd", "hwids": [ "1d9f3ebb-96de-5dd6-8c88-38308b0c1c44", "578dd7d5-5871-5bd5-92a9-be07f1067b92", "ed647f93-3075-598b-9d89-d0f30ec11707", "f6cd4a9f-9632-516e-b748-65952f7380c5", "a5a4e3c1-5922-5ed6-b78e-9f0ea873a988", "a20ae3ec-49a1-5cb5-acb8-5d31c77b105a", "8cfd85bb-0d77-59df-8546-264239be475e", "513976f8-3f51-5b42-9ae0-931ce23c5f38", "86a0d770-3ca1-57fa-ac05-413481c00a24", "5c20e964-d530-5dd7-9efd-4aed9e73c3cb", "d93b21c0-5ed9-5955-911a-5b15f114d786", "431ff9e9-cd92-51c1-8917-46b0a0ef147c", "e093d715-70f7-51f4-b6c8-b4a7e31def85", "62631c9b-2642-5d4f-b7e2-1b917809d08d", "6de5d951-d755-576b-bd09-c5cf66b27234", "82fa4a02-8c3c-55f9-b0c9-e8feb669fd3a", "34e7fadd-9c7d-5f91-ba7f-cedb04d59b9a", "99431f53-09a1-5869-be79-65e2fa3f341d" ] } ubustub-1/hwids/json/x1e80100-asus-vivobook-s15.json000066400000000000000000000017611504315023600221740ustar00rootroot00000000000000{ "type": "devicetree", "name": "ASUSTeK COMPUTER INC. ASUS Vivobook S 15", "compatible": "asus,vivobook-s15", "hwids": [ "6d634332-21fc-57c8-bc6b-e0f800f69f95", "d0fce8d6-a709-5bf0-8be0-6ac6ab44b8e0", "80430e03-90f0-5355-84b2-28fb17367203", "fa342b0a-9e22-541f-8e95-93106778f97d", "137a5f94-8fcf-5581-8ac6-70d50fdba4a6", "3a3ef092-d5f1-5d4d-acea-70b38ef56e53", "a6debedb-f954-5aa1-8260-4dc3b567c95f", "f3a6ca3e-4791-5bb0-915e-0b31856ec19c", "4262e277-58d3-5ac4-9858-c0751ad06f5c", "f54cd4e6-3666-5b56-abd3-a5f2df50c534", "807fe49f-cfd2-537d-b635-47bec9e36baf", "51df1ece-cd39-547a-8f9f-8f036fcfe752", "665276be-80c5-5e5d-929f-fa85d18e2d50", "05cd2c3f-53cc-5239-94db-f7a00903ac1d", "65605ed1-09e2-57aa-bd0f-a26c1d35433f", "c71e903b-4255-56cb-b961-a8f87b452cbe", "1b6a0689-3f70-57e0-8bf3-39a8a74213e8", "9d1b57fb-8282-5287-bd50-3c93d43921fa" ] } ubustub-1/hwids/json/x1e80100-crd.json000066400000000000000000000012731504315023600175250ustar00rootroot00000000000000{ "type": "devicetree", "name": "Qualcomm SCP_HAMOA", "compatible": "qcom,x1e80100-crd", "hwids": [ "e73870a5-90e8-528d-93fd-3da59f78df18", "2405af0b-d21d-5196-a228-4acffe7b3a10", "8fa88c58-23eb-5aea-9ea7-c4a98ded7352", "7faef667-9eb2-53f4-9764-26fe0e92fbff", "b6d4eee8-30f3-564a-8246-e83935cf8dbb", "4bb05d50-6c4f-525d-a9ec-8924afd6edea", "339fc6d2-e0f4-5226-9dd9-62c4dc41881d", "b36a40fa-4640-5b1b-8fa1-6dbde103c80d", "0d601876-0ac6-533e-8386-3a58203d8c33", "d52e3fb6-202c-5cfa-a27c-e3ffe15339fb", "361b3d63-be90-52c2-8798-a05fbd68b773", "d86bea02-5d71-5ee5-98dc-4f74d5777dde" ] } ubustub-1/hwids/json/x1e80100-dell-latitude-7455.json000066400000000000000000000015141504315023600221060ustar00rootroot00000000000000{ "type": "devicetree", "name": "Dell Inc. Latitude", "compatible": "dell,latitude-7455", "hwids": [ "903e3a6f-e14b-5643-9d55-244f917aadb6", "59e5c810-9e60-5a89-8665-db36c56b34d6", "2b9277cd-85b1-51ee-9a38-d477632532da", "6e01222b-b2aa-531e-b95f-0e4b2a063364", "93055898-8c85-50e7-adde-8115f194579a", "b3e5b59d-84ae-597d-9222-8a4d48480bc3", "4f73f73b-e639-5353-bbf7-d851e48f18fc", "68822228-a3e0-5b12-942d-9408751405d1", "41b0b5d7-ad12-5d86-9a3d-826f9b20adcc", "a26f8d6d-d9ab-5705-939a-aec8fed37cd4", "cb846e91-7a9f-564f-8f33-6cf5bc04a5b8", "85d38fda-fc0e-5c6f-808f-076984ae7978", "683e4579-8440-5bc1-89ac-dfcd7c25b307", "fb7493ec-9634-5c5a-9f26-69cbf9b92460", "36cb5c6e-fb91-55e9-8077-e004f2b1ddad" ] } ubustub-1/hwids/json/x1e80100-dell-xps13-9345.json000066400000000000000000000015041504315023600212500ustar00rootroot00000000000000{ "type": "devicetree", "name": "Dell Inc. XPS", "compatible": "dell,xps13-9345", "hwids": [ "eedeb5d9-1a0e-56e6-9137-eb6a723e58d1", "1eb87d70-2f37-5f18-85de-30e46c17d540", "1d1baf60-e2f3-5821-9d98-19a131bf8d93", "7c7c2920-cb59-56ad-bc8a-939e803b0192", "940c6349-f0a5-54ba-8deb-10e709e0b76c", "3b9a1d76-f2e8-52e8-84de-14c5942b3d41", "3c2649a7-2275-5130-a0c4-cc5f9809a2c1", "36e8dd88-512d-5a74-86a4-039333f9e15a", "e656b5f2-69c3-55da-bf22-4dd58d5f6d4f", "bc685cec-e979-5cb9-bf02-e15586c7cb4b", "81972cb8-6fc7-5e08-b140-b0063ed4fefa", "61178075-a8fd-563c-9045-44227d8c121f", "5c163113-9296-5c8d-a92d-ae04eb59a0f7", "1302793c-52b1-5354-b1cf-f2cd9206c157", "85d38fda-fc0e-5c6f-808f-076984ae7978" ] } ubustub-1/hwids/json/x1e80100-hp-omnibook-x14.json000066400000000000000000000015231504315023600216070ustar00rootroot00000000000000{ "type": "devicetree", "name": "HP 103C_5335M8 HP OmniBook X", "compatible": "hp,omnibook-x14", "hwids": [ "045dfd0f-068b-5e57-86bd-f41b4b906006", "ca5dab4f-a301-53c6-b753-c2db56172e0a", "811126e6-4aee-5f9e-827d-d0f12f6a6f00", "6a4511bc-0a3b-5b10-9c8b-dbcb834ecd83", "abb2ffec-2acd-5750-8dfd-c3845fd4bf2a", "1a192aee-2cfd-5ab5-95f9-8093218a48ef", "eaab52c6-ed22-5e1b-b788-fc5a0531291d", "848aeb1d-302b-5b6b-9109-0f4632535915", "5d43face-6ba8-5d41-8914-12f3410bbcf9", "4c84c882-b54c-58d5-b412-26bcdf254c3e", "2ae478e9-ef65-5485-bb06-a233136e53c7", "93f84748-c854-5d6b-b78a-13c2361e0758", "54500b82-f7ae-592d-ae68-8c8e362a1475", "68d24be5-01b6-5d88-83fb-df2bcfa879aa", "ad0b7f58-06f2-50b9-856b-343f54261425" ] } ubustub-1/hwids/json/x1e80100-lenovo-yoga-slim7x.json000066400000000000000000000015231504315023600224330ustar00rootroot00000000000000{ "type": "devicetree", "name": "LENOVO Yoga Slim 7 14Q8X9", "compatible": "lenovo,yoga-slim7x", "hwids": [ "3fb1e5ba-05cd-5153-ad64-1d8bc6dc7a1b", "d99f6cb2-4a96-5e4a-8e29-19d52dfc2870", "6d53c38f-6adb-578b-a418-2abda4d8485d", "8073dbed-501f-5f5e-a619-4cdd9c00e865", "d27cf20e-e185-578e-bd46-f4cc3a718bb2", "8477f828-512b-56cf-af55-c711a6831551", "f7f92b85-ff01-5e93-a453-c7f91029aa55", "0700776d-0de7-5ea7-b9bf-77e0454d35e1", "ee39b629-4187-5ff7-84c0-e354555562cd", "fdb12a4f-1e8b-524e-97b5-feef23a8a8da", "63429d43-c970-570d-aaa7-54300924e0c5", "8f143f12-40dc-5801-8e61-08a88cd68c1e", "e093d715-70f7-51f4-b6c8-b4a7e31def85", "71d86d4d-02f8-5566-a7a1-529cef184b7e", "6de5d951-d755-576b-bd09-c5cf66b27234" ] } ubustub-1/hwids/json/x1p42100-asus-zenbook-a14.json000066400000000000000000000017741504315023600217770ustar00rootroot00000000000000{ "type": "devicetree", "name": "ASUSTeK COMPUTER INC. ASUS Zenbook A14", "compatible": "asus,zenbook-a14-ux3407qa-oled", "hwids": [ "c6d100b1-9de7-5636-a3cc-f28fa46fb926", "85f50d27-f4cb-54df-9aae-f6f09700b132", "8a72a2ea-3971-55e3-b982-cb6b82868f0e", "a034eff6-2891-5de0-b0db-9c5ff350b968", "a5b5becc-2a55-5017-b159-087f3846da26", "59793319-4344-5755-9194-17f29f030d5d", "14643426-35fa-5a20-bc31-3b6095d2b451", "24652d54-00f4-59ae-96fb-f7adbfa4a939", "a8425d85-573a-56f8-9d9d-98a196d712fa", "7e6d3df4-bf5f-59ab-ad7b-e00677c0ae5a", "00bc5418-646d-5bab-b772-4efb06f4e7f1", "c5647aaf-bd0a-5863-bdda-49afd00c5329", "665276be-80c5-5e5d-929f-fa85d18e2d50", "7c5098e1-fa78-597c-a6ba-8b69ccc1cf75", "65605ed1-09e2-57aa-bd0f-a26c1d35433f", "3ca4e2d9-50df-51a5-a87f-4636d425e97d", "0b8b84da-462b-5620-bdb5-70272e0ddd94", "9d1b57fb-8282-5287-bd50-3c93d43921fa" ] } ubustub-1/hwids/txt/000077500000000000000000000000001504315023600146415ustar00rootroot00000000000000ubustub-1/hwids/txt/msm8998-lenovo-miix-630-81f1.txt000066400000000000000000000034231504315023600217710ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: 8WCN25WW Manufacturer: LENOVO Family: Miix 630 ProductName: 81F1 ProductSku: LENOVO_MT_81F1_BU_idea_FM_Miix 630 EnclosureKind: 32 BaseboardManufacturer: LENOVO BaseboardProduct: LNVNB161216 Hardware IDs ------------ not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown {16a55446-eba9-5f97-80e3-5e39d8209bc3} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {c4c9a6be-5383-5de7-af35-c2de505edec8} <- Manufacturer + Family + ProductName + ProductSku {14f581d2-d059-5cb2-9f8b-56d8be7932c9} <- Manufacturer + Family + ProductName {a51054fb-5eef-594a-a5a0-cd87632d0aea} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {307ab358-ed84-57fe-bf05-e9195a28198d} <- Manufacturer + ProductSku {7e613574-5445-5797-9567-2d0ed86e6ffa} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {b0f4463c-f851-5ec3-b031-2ccb873a609a} <- Manufacturer + ProductName {08b75d1f-6643-52a1-9bdd-071052860b33} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {dacf4a59-8e87-55c5-8b93-6912ded6bf7f} <- Manufacturer + Family {d0a8deb1-4cb5-50cd-bdda-595cfc13230c} <- Manufacturer + EnclosureKind {71d86d4d-02f8-5566-a7a1-529cef184b7e} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer Extra Hardware IDs ------------------ {34df58d6-b605-50aa-9313-9b34f5c4b6fc} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {e0a96696-f0a6-5466-a6db-207fbe8bae3c} <- Manufacturer + Family + ProductName + BiosVendor {99431f53-09a1-5869-be79-65e2fa3f341d} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/sc7180-acer-aspire1.txt000066400000000000000000000035131504315023600206030ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Phoenix BiosVersion: V1.13 BiosMajorRelease: 1 BiosMinorRelease: 13 FirmwareMajorRelease: 01 FirmwareMinorRelease: 07 Manufacturer: Acer Family: Aspire 1 ProductName: Aspire A114-61 ProductSku: EnclosureKind: a BaseboardManufacturer: S7C BaseboardProduct: Daisy_7C Hardware IDs ------------ {45d37dbe-40fb-57bd-a257-55f422d4dc0a} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {373bfde5-ffaa-504c-84f3-f8f5357dfc29} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {e12521bf-0ed8-5406-af87-adad812c57c5} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {faa12ed4-bd49-5471-8f74-75c2267c3b46} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {965e3681-de3b-5e39-bb62-7d4917d7e36f} <- Manufacturer + Family + ProductName + ProductSku {82fe1869-361c-56b2-b853-631747e64aa7} <- Manufacturer + Family + ProductName {7e15f49e-04b4-5d56-a567-e7a15ba2aca1} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {7c107a7f-2d77-51aa-aef8-8d777e26ffbc} <- Manufacturer + ProductSku {68b38fff-aadc-512c-937b-99d9c13eb484} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {260192d4-06d4-5124-ab46-ba210f4c14d7} <- Manufacturer + ProductName {175f000b-3d05-5c01-aedd-817b1a141f93} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {24277a94-7064-500f-9854-5264f20cfa99} <- Manufacturer + Family {92dcc94d-48f7-5ee8-b9ec-a6393fb7a484} <- Manufacturer + EnclosureKind {d234a917-df0b-5453-a3d9-f27c06307395} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {1e301734-5d49-5df4-9ed2-aa1c0a9dddda} <- Manufacturer ubustub-1/hwids/txt/sc8180x-lenovo-flex-5g-81xe.txt000066400000000000000000000036051504315023600220540ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: EACN41WW(V1.13) BiosMajorRelease: 1 BiosMinorRelease: 41 FirmwareMajorRelease: 01 FirmwareMinorRelease: 29 Manufacturer: LENOVO Family: Yoga 5G 14Q8CX05 ProductName: 81XE ProductSku: LENOVO_MT_81XE_BU_idea_FM_Yoga 5G 14Q8CX05 EnclosureKind: 1f BaseboardManufacturer: LENOVO BaseboardProduct: LNVNB161216 Hardware IDs ------------ {ea646c11-3da1-5c8d-9346-8ff156746650} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {5100eeed-c5e2-5b74-9c24-a22ca0644826} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {ddb3bcda-db7b-579d-9dd9-bcc4f5b052b8} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {fb364c09-efc0-5d16-ac97-0a3e6235b16c} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {7e7007ac-603c-55ef-bb77-3548784b9578} <- Manufacturer + Family + ProductName + ProductSku {566b9ae8-a7fd-5c44-94d6-bac3e4cf38a7} <- Manufacturer + Family + ProductName {6f3bdfb7-f832-5c5f-9777-9e3db35e22a6} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {c4ea686c-c56c-5e8e-a91e-89056683d417} <- Manufacturer + ProductSku {a1a13249-2689-5c6d-a43f-98af040284c4} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {01439aea-e75c-5fbb-8842-18dcd1a7b8b3} <- Manufacturer + ProductName {65ab9f32-bbc8-52d3-87f9-b618fda7c07e} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {41ba2569-88df-57d4-b5e3-350ff985434a} <- Manufacturer + Family {32b7e294-a252-5a72-b3c6-6197f08c64f1} <- Manufacturer + EnclosureKind {71d86d4d-02f8-5566-a7a1-529cef184b7e} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer ubustub-1/hwids/txt/sc8180x-lenovo-flex-5g-82ak.txt000066400000000000000000000036061504315023600220350ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: EACN43WW(V1.15) BiosMajorRelease: 1 BiosMinorRelease: 43 FirmwareMajorRelease: 01 FirmwareMinorRelease: 2b Manufacturer: LENOVO Family: Flex 5G 14Q8CX05 ProductName: 82AK ProductSku: LENOVO_MT_82AK_BU_idea_FM_Flex 5G 14Q8CX05 EnclosureKind: 1f BaseboardManufacturer: LENOVO BaseboardProduct: LNVNB161216 Hardware IDs ------------ {ad47f2e9-2f8c-5cd1-a44e-82f35a43e44e} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {997c1c76-5595-5300-9f58-94d2c6ffc586} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {b9bf941f-3a32-57da-b609-5fff7fb382cd} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {ea658d2b-f644-555d-9b72-e1642401a795} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {fb5c3077-39d5-5a44-97ce-2d3be5f6bfec} <- Manufacturer + Family + ProductName + ProductSku {16551bd5-37b0-571d-a94c-da61a9cfccf5} <- Manufacturer + Family + ProductName {df3ecc56-b61b-5f8e-896f-801a42b536d6} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {06675172-9a6e-5276-a505-d205688a87f0} <- Manufacturer + ProductSku {23dcfb84-d132-5f60-878e-64fe0b9417d6} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {12c0e5b0-8886-5444-b42b-93692fa736df} <- Manufacturer + ProductName {39fca706-c9a2-54d4-8c7c-d5e292d0a725} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {6e266ee4-0ba4-561c-9758-9fd4876af2e2} <- Manufacturer + Family {32b7e294-a252-5a72-b3c6-6197f08c64f1} <- Manufacturer + EnclosureKind {71d86d4d-02f8-5566-a7a1-529cef184b7e} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer ubustub-1/hwids/txt/sc8280xp-huawei-gaokun3.txt000066400000000000000000000042031504315023600215250ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: HUAWEI BiosVersion: 2.16 BiosMajorRelease: 2 BiosMinorRelease: 16 FirmwareMajorRelease: 02 FirmwareMinorRelease: 10 Manufacturer: HUAWEI Family: MateBook E ProductName: GK-W7X ProductSku: C233 EnclosureKind: 20 BaseboardManufacturer: HUAWEI BaseboardProduct: GK-W7X-PCB Hardware IDs ------------ {80c86c24-c7a7-5714-abf2-4c48f348cecc} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {1c2effc1-1038-584d-ae8b-7c912c8e9504} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {6eb75906-3a4e-5de4-94c5-374d8f9723e5} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {4f04f31f-17f0-583f-802f-82c3a0b34128} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {e1b94e53-0f20-5d01-abfc-cfb348544a31} <- Manufacturer + Family + ProductName + ProductSku {b866fc5c-261b-56d8-99e8-03ea0646af8f} <- Manufacturer + Family + ProductName {d8846172-f0a0-55ba-bf41-55641f588ea7} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {7ea8b73b-2cbb-562b-aecc-7f0f64c42630} <- Manufacturer + ProductSku {3eb6683b-0153-5365-81c6-cc599783e9c7} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {e5a0ed2b-7fed-5e2d-94ed-43dbaf0b9ccc} <- Manufacturer + ProductName {0c78ef16-4fe0-5e33-908e-b038949ee608} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {8187555f-3681-5463-a0fa-e6b74e49d4c1} <- Manufacturer + Family {39bed59d-bfe0-5938-9a76-b2f4739af786} <- Manufacturer + EnclosureKind {c562b393-1c28-5cc3-a77c-c13c798e5698} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {0df4aa3f-2706-51d4-9296-80119e47f1e1} <- Manufacturer Extra Hardware IDs ------------------ {e98c95a8-b50e-5d8b-b2db-c679a39163df} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {13311789-793f-5d95-942c-3b6414a8ad1a} <- Manufacturer + Family + ProductName + BiosVendor {04798471-7c9b-5189-b99b-4d19e1a6fa89} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/sc8280xp-lenovo-thinkpad-x13s-21bx.txt000066400000000000000000000036221504315023600233520ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: N3HET88W (1.60 ) BiosMajorRelease: 1 BiosMinorRelease: 60 FirmwareMajorRelease: 01 FirmwareMinorRelease: 17 Manufacturer: LENOVO Family: ThinkPad X13s Gen 1 ProductName: 21BXCTO1WW ProductSku: LENOVO_MT_21BX_BU_Think_FM_ThinkPad X13s Gen 1 EnclosureKind: a BaseboardManufacturer: LENOVO BaseboardProduct: 21BXCTO1WW Hardware IDs ------------ {810e34c6-cc69-5e36-8675-2f6e354272d3} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {f22c935e-2dc8-5949-9486-09bbf10361b2} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {abdbb2cb-ab52-5674-9d0a-2e2cb69bcbb4} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {ddf28a3f-43fc-54a4-a6a7-4cba5ad46b3e} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {4df470e6-7878-5b0f-b2e0-733d5d9fa228} <- Manufacturer + Family + ProductName + ProductSku {3ad863ab-0181-5a2f-9cc1-70eedc446da9} <- Manufacturer + Family + ProductName {69c47e1e-fde2-5062-b777-acbeab73784b} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {3486eccc-d0ac-534a-9e2f-a1c18bc310c6} <- Manufacturer + ProductSku {c869f39e-f205-5ca0-be7b-d90f90ef5556} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {b470d002-ad8e-5d5c-a7bf-bb1333f2ce4b} <- Manufacturer + ProductName {64b71f12-4341-5e5c-b7cd-25b6503799e3} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {f249803d-0d95-54f3-a28f-f26c14a03f3b} <- Manufacturer + Family {e093d715-70f7-51f4-b6c8-b4a7e31def85} <- Manufacturer + EnclosureKind {156c9b34-bedb-5bfd-ae1f-ef5d2a994967} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer ubustub-1/hwids/txt/sc8280xp-lenovo-thinkpad-x13s-21by.txt000066400000000000000000000036211504315023600233520ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: N3HET86W (1.58 ) BiosMajorRelease: 1 BiosMinorRelease: 58 FirmwareMajorRelease: 01 FirmwareMinorRelease: 17 Manufacturer: LENOVO Family: ThinkPad X13s Gen 1 ProductName: 21BYS03Y00 ProductSku: LENOVO_MT_21BY_BU_Think_FM_ThinkPad X13s Gen 1 EnclosureKind: a BaseboardManufacturer: LENOVO BaseboardProduct: 21BYS03Y00 Hardware IDs ------------ {b265d777-007e-56e5-b0e2-bd666ab867be} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {3f9d2d91-73b2-5316-8c72-a0ecb3f0dae5} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {4b189129-8eb2-585c-a1bb-a4cfc979433a} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {fbf92a11-bb6f-5adb-b5a7-8abf9acbd7d9} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {0909a1c3-3a02-59a0-b1ea-04f1449c104f} <- Manufacturer + Family + ProductName + ProductSku {69acf6bf-ed33-5806-857f-c76971d7061e} <- Manufacturer + Family + ProductName {ddfbdaa2-7c46-5103-be64-84a9f88c485f} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {b41f58ed-7631-561f-9b0c-449a9c293afa} <- Manufacturer + ProductSku {9f47e28f-e1ee-5cb5-b4ce-8f0605752b3d} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {873455fb-b2c5-5c0c-9c2c-90e80d44da57} <- Manufacturer + ProductName {a1dfe209-99e5-5ff2-9922-aa4c11491b49} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {f249803d-0d95-54f3-a28f-f26c14a03f3b} <- Manufacturer + Family {e093d715-70f7-51f4-b6c8-b4a7e31def85} <- Manufacturer + EnclosureKind {920b6e26-11c6-5beb-8643-fcf5cd74033f} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer ubustub-1/hwids/txt/sc8280xp-microsoft-blackrock.txt000066400000000000000000000036271504315023600226450ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Microsoft Corporation BiosVersion: 12.6.235 BiosMajorRelease: 255 BiosMinorRelease: 255 FirmwareMajorRelease: ff FirmwareMinorRelease: ff Manufacturer: Microsoft Corporation Family: Surface ProductName: Windows Dev Kit 2023 ProductSku: 2043 EnclosureKind: 3 BaseboardManufacturer: Microsoft Corporation BaseboardProduct: Windows Dev Kit 2023 Hardware IDs ------------ {69ba0503-ca94-5fa3-b78c-5fa21a66c620} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {ad2ee931-a048-5253-b350-98c482670765} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {5bd24fc5-5edb-51f6-82e6-31a9ef954c5b} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {d67e799e-2ba7-555a-a874-a0523a8b3b11} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {813677fa-6d11-5756-a44d-dde0f552d3f6} <- Manufacturer + Family + ProductName + ProductSku {ce83144b-b123-59e5-8a9a-0c1a13643fc4} <- Manufacturer + Family + ProductName {53b87f48-fc47-54e9-ade5-f1a95e885681} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {046fefee-341b-5c40-b0a3-1c647d31b500} <- Manufacturer + ProductSku {f59639f4-4970-5706-9a75-519dd059f69e} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {08f06457-aa19-51c5-be4c-0087ce4fa2ed} <- Manufacturer + ProductName {11b80238-dbee-57bc-8b26-83c9e5b4057d} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {ca2e5189-1d32-509f-88a0-d4ebcc721899} <- Manufacturer + Family {7ce6d32b-3711-5701-b31a-cc79f61a5719} <- Manufacturer + EnclosureKind {2c1da402-8915-572d-a493-c966d32f96cb} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {cc0aea32-ad2c-5013-8bed-cede6be8c9f4} <- Manufacturer ubustub-1/hwids/txt/sc8280xp-microsoft-surface-pro-9-5G.txt000066400000000000000000000036371504315023600235600ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Microsoft Corporation BiosVersion: 17.4.235 BiosMajorRelease: 255 BiosMinorRelease: 255 FirmwareMajorRelease: ff FirmwareMinorRelease: ff Manufacturer: Microsoft Corporation Family: Surface ProductName: Surface Pro 9 ProductSku: Surface_Pro_9_With_5G_1996 EnclosureKind: 9 BaseboardManufacturer: Microsoft Corporation BaseboardProduct: Surface Pro 9 Hardware IDs ------------ {e3d941fa-2bfa-5875-8efd-87ce997f8338} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {a659ee2b-502d-50f7-9921-bdbd34734e0b} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {5caa88bc-ea9b-5d73-a69a-89024bfff854} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {c0cf7078-c325-5cf6-966b-3bbbc155275b} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {6309fbb9-68f4-54f9-bbc9-b3ca9685b48c} <- Manufacturer + Family + ProductName + ProductSku {9d70dcfd-f56b-58bf-b1bd-a1b8f2b0ec7e} <- Manufacturer + Family + ProductName {9bac72c6-83f6-5e21-af8e-bc1f5c2b7cc8} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {94fb24a7-ff7a-5d70-9ac8-518a9e44ea64} <- Manufacturer + ProductSku {009d2337-4f76-514e-b2c1-b2816447b048} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {3a486e6f-3b0a-5603-a483-503381d3d8c3} <- Manufacturer + ProductName {636b6071-7848-50d5-b0b5-6290c49e9306} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {ca2e5189-1d32-509f-88a0-d4ebcc721899} <- Manufacturer + Family {aca387a9-183e-5da9-8f9d-f460c3f50f54} <- Manufacturer + EnclosureKind {7fa0755a-ec45-59cd-a206-bb9a956b030f} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {cc0aea32-ad2c-5013-8bed-cede6be8c9f4} <- Manufacturer ubustub-1/hwids/txt/sdm850-lenovo-yoga-c630.txt000066400000000000000000000036031504315023600213320ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: 9UCN33WW(V2.06) BiosMajorRelease: 1 BiosMinorRelease: 33 FirmwareMajorRelease: 01 FirmwareMinorRelease: 21 Manufacturer: LENOVO Family: YOGA C630-13Q50 ProductName: 81JL ProductSku: LENOVO_MT_81JL_BU_idea_FM_YOGA C630-13Q50 EnclosureKind: 20 BaseboardManufacturer: LENOVO BaseboardProduct: LNVNB161216 Hardware IDs ------------ {b8c71349-3669-56f3-99ee-ae473a2edd96} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {d17c132e-f06e-5e38-8084-9cd642dd9b34} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {8f56cf17-7bdd-5414-832d-97cd26837114} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {b323d38a-88c6-5cf6-af0d-0db3f3c2560d} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {43b71948-9c47-5372-a5cb-18db47bb873f} <- Manufacturer + Family + ProductName + ProductSku {67a23be6-42a6-5900-8325-847a318ce252} <- Manufacturer + Family + ProductName {94f73d29-3981-59a8-8f25-214f84d1522a} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {5ca3cf2b-d6e9-5b54-93f7-1cebd7b3704f} <- Manufacturer + ProductSku {81f308c0-db65-50c2-a660-52e06fc0ff9f} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {30b031c0-9de7-5d31-a61c-dee772871b7d} <- Manufacturer + ProductName {382926c0-ce35-53af-8ff9-ca9cc06cfc7b} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {dd3a12ef-e928-519d-83d7-6674a2ae0ffa} <- Manufacturer + Family {6c95fc34-96cc-5c9f-8e78-6baaffde78ce} <- Manufacturer + EnclosureKind {71d86d4d-02f8-5566-a7a1-529cef184b7e} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer ubustub-1/hwids/txt/x1e001de-devkit.txt000066400000000000000000000025771504315023600201300ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Qualcomm Technologies, Inc. BiosVersion: 6.0.240901.BOOT.MXF.2.4-00468-HAMOA-1 Manufacturer: Qualcomm Family: SCP_HAMOA ProductName: Snapdragon-Devkit ProductSku: 6 Hardware IDs ------------ not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown not available as 'BaseboardManufacturer' unknown {baa7a649-12d8-56c7-93c5-a4e10f4852be} <- Manufacturer + Family + ProductName + ProductSku {c8e75ab8-555c-5952-a3e3-5b607bea031d} <- Manufacturer + Family + ProductName not available as 'BaseboardManufacturer' unknown {4bb05d50-6c4f-525d-a9ec-8924afd6edea} <- Manufacturer + ProductSku not available as 'BaseboardManufacturer' unknown {830bd4a2-2498-55cf-b561-48f7dc5f4820} <- Manufacturer + ProductName not available as 'BaseboardManufacturer' unknown {b36a40fa-4640-5b1b-8fa1-6dbde103c80d} <- Manufacturer + Family not available as 'EnclosureKind' unknown not available as 'BaseboardManufacturer' unknown {0d601876-0ac6-533e-8386-3a58203d8c33} <- Manufacturer Extra Hardware IDs ------------------ {f37dc44b-0be4-5a70-86bd-81f3dacff2e9} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {9cba20d0-17ad-559f-94cd-cfcbbf5f71f5} <- Manufacturer + Family + ProductName + BiosVendor {d86bea02-5d71-5ee5-98dc-4f74d5777dde} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e78100-lenovo-thinkpad-t14s-21n1.txt000066400000000000000000000043051504315023600230510ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: N42ET53W (1.27 ) BiosMajorRelease: 1 BiosMinorRelease: 27 FirmwareMajorRelease: 01 FirmwareMinorRelease: 0f Manufacturer: LENOVO Family: ThinkPad T14s Gen 6 ProductName: 21N10001US ProductSku: LENOVO_MT_21N1_BU_Think_FM_ThinkPad T14s Gen 6 EnclosureKind: a BaseboardManufacturer: LENOVO BaseboardProduct: 21N10001US Hardware IDs ------------ {c81fee2f-cf41-5d5a-8c7b-afd6585b1d81} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {a9b59fea-e841-508a-a245-3a2d8d2802de} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {74593764-b6b9-58e9-bedc-93ebbb1eb057} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {e5d83424-0ecb-5632-b7b1-500f04e82725} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {76032e78-67a8-5dab-8512-157bfcfb8f75} <- Manufacturer + Family + ProductName + ProductSku {dd83478e-e01b-5631-ae74-92ae275a9b4e} <- Manufacturer + Family + ProductName {791ecd9d-1547-58e6-b72a-5ce417b729dd} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {8c602147-5363-5374-859e-8b7fe2d4d3ce} <- Manufacturer + ProductSku {498d60ae-9b1d-5b67-8abd-af571babfa94} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {acbac5af-aa6a-5690-88f3-e910f04a7ead} <- Manufacturer + ProductName {5180bc01-5d18-5870-b955-969da38b2647} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {431ff9e9-cd92-51c1-8917-46b0a0ef147c} <- Manufacturer + Family {e093d715-70f7-51f4-b6c8-b4a7e31def85} <- Manufacturer + EnclosureKind {c124cecf-e6dc-5d35-a320-712980cfb68d} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer Extra Hardware IDs ------------------ {19b622ef-27fe-5c2e-bc53-13a79b862c65} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {ac09e50f-9b3b-53c0-9752-377c3a0baaa0} <- Manufacturer + Family + ProductName + BiosVendor {99431f53-09a1-5869-be79-65e2fa3f341d} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e78100-lenovo-thinkpad-t14s-21n2.txt000066400000000000000000000043041504315023600230510ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: N42ET88W (2.18 ) BiosMajorRelease: 2 BiosMinorRelease: 18 FirmwareMajorRelease: 01 FirmwareMinorRelease: 1b Manufacturer: LENOVO Family: ThinkPad T14s Gen 6 ProductName: 21N2ZC5QUS ProductSku: LENOVO_MT_21N2_BU_Think_FM_ThinkPad T14s Gen 6 EnclosureKind: a BaseboardManufacturer: LENOVO BaseboardProduct: 21N2ZC5QUS Hardware IDs ------------ {1d9f3ebb-96de-5dd6-8c88-38308b0c1c44} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {578dd7d5-5871-5bd5-92a9-be07f1067b92} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {ed647f93-3075-598b-9d89-d0f30ec11707} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {f6cd4a9f-9632-516e-b748-65952f7380c5} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {a5a4e3c1-5922-5ed6-b78e-9f0ea873a988} <- Manufacturer + Family + ProductName + ProductSku {a20ae3ec-49a1-5cb5-acb8-5d31c77b105a} <- Manufacturer + Family + ProductName {8cfd85bb-0d77-59df-8546-264239be475e} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {513976f8-3f51-5b42-9ae0-931ce23c5f38} <- Manufacturer + ProductSku {86a0d770-3ca1-57fa-ac05-413481c00a24} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {5c20e964-d530-5dd7-9efd-4aed9e73c3cb} <- Manufacturer + ProductName {d93b21c0-5ed9-5955-911a-5b15f114d786} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {431ff9e9-cd92-51c1-8917-46b0a0ef147c} <- Manufacturer + Family {e093d715-70f7-51f4-b6c8-b4a7e31def85} <- Manufacturer + EnclosureKind {62631c9b-2642-5d4f-b7e2-1b917809d08d} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer Extra Hardware IDs ------------------ {82fa4a02-8c3c-55f9-b0c9-e8feb669fd3a} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {34e7fadd-9c7d-5f91-ba7f-cedb04d59b9a} <- Manufacturer + Family + ProductName + BiosVendor {99431f53-09a1-5869-be79-65e2fa3f341d} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e80100-asus-vivobook-s15.txt000066400000000000000000000043151504315023600217060ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Insyde BiosVersion: S5507QAD.307 BiosMajorRelease: 1 BiosMinorRelease: 27 FirmwareMajorRelease: 03 FirmwareMinorRelease: 02 Manufacturer: ASUSTeK COMPUTER INC. Family: ASUS Vivobook S 15 ProductName: ASUS Vivobook S 15 S5507QA_S5507QAD ProductSku: (null) EnclosureKind: a BaseboardManufacturer: ASUSTeK COMPUTER INC. BaseboardProduct: S5507QAD Hardware IDs ------------ {6d634332-21fc-57c8-bc6b-e0f800f69f95} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {d0fce8d6-a709-5bf0-8be0-6ac6ab44b8e0} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {80430e03-90f0-5355-84b2-28fb17367203} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {fa342b0a-9e22-541f-8e95-93106778f97d} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {137a5f94-8fcf-5581-8ac6-70d50fdba4a6} <- Manufacturer + Family + ProductName + ProductSku {3a3ef092-d5f1-5d4d-acea-70b38ef56e53} <- Manufacturer + Family + ProductName {a6debedb-f954-5aa1-8260-4dc3b567c95f} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {f3a6ca3e-4791-5bb0-915e-0b31856ec19c} <- Manufacturer + ProductSku {4262e277-58d3-5ac4-9858-c0751ad06f5c} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {f54cd4e6-3666-5b56-abd3-a5f2df50c534} <- Manufacturer + ProductName {807fe49f-cfd2-537d-b635-47bec9e36baf} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {51df1ece-cd39-547a-8f9f-8f036fcfe752} <- Manufacturer + Family {665276be-80c5-5e5d-929f-fa85d18e2d50} <- Manufacturer + EnclosureKind {05cd2c3f-53cc-5239-94db-f7a00903ac1d} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {65605ed1-09e2-57aa-bd0f-a26c1d35433f} <- Manufacturer Extra Hardware IDs ------------------ {c71e903b-4255-56cb-b961-a8f87b452cbe} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {1b6a0689-3f70-57e0-8bf3-39a8a74213e8} <- Manufacturer + Family + ProductName + BiosVendor {9d1b57fb-8282-5287-bd50-3c93d43921fa} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e80100-crd.txt000066400000000000000000000034021504315023600172350ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Qualcomm Technologies, Inc. BiosVersion: 6.0.240718.BOOT.MXF.2.4-00515-HAMOA-1 BiosMajorRelease: 255 BiosMinorRelease: 255 FirmwareMajorRelease: 00 FirmwareMinorRelease: 14 Manufacturer: Qualcomm Family: SCP_HAMOA ProductName: CRD ProductSku: 6 Hardware IDs ------------ {e73870a5-90e8-528d-93fd-3da59f78df18} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {2405af0b-d21d-5196-a228-4acffe7b3a10} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {8fa88c58-23eb-5aea-9ea7-c4a98ded7352} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease not available as 'BaseboardManufacturer' unknown {7faef667-9eb2-53f4-9764-26fe0e92fbff} <- Manufacturer + Family + ProductName + ProductSku {b6d4eee8-30f3-564a-8246-e83935cf8dbb} <- Manufacturer + Family + ProductName not available as 'BaseboardManufacturer' unknown {4bb05d50-6c4f-525d-a9ec-8924afd6edea} <- Manufacturer + ProductSku not available as 'BaseboardManufacturer' unknown {339fc6d2-e0f4-5226-9dd9-62c4dc41881d} <- Manufacturer + ProductName not available as 'BaseboardManufacturer' unknown {b36a40fa-4640-5b1b-8fa1-6dbde103c80d} <- Manufacturer + Family not available as 'EnclosureKind' unknown not available as 'BaseboardManufacturer' unknown {0d601876-0ac6-533e-8386-3a58203d8c33} <- Manufacturer Extra Hardware IDs ------------------ {d52e3fb6-202c-5cfa-a27c-e3ffe15339fb} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {361b3d63-be90-52c2-8798-a05fbd68b773} <- Manufacturer + Family + ProductName + BiosVendor {d86bea02-5d71-5ee5-98dc-4f74d5777dde} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e80100-dell-latitude-7455.txt000066400000000000000000000033771504315023600216330ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Dell Inc. BiosVersion: 2.8.0 Manufacturer: Dell Inc. Family: Latitude ProductName: Latitude 7455 ProductSku: 0C85 EnclosureKind: 10 BaseboardManufacturer: Dell Inc. BaseboardProduct: 0FK7MX Hardware IDs ------------ not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown {903e3a6f-e14b-5643-9d55-244f917aadb6} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {59e5c810-9e60-5a89-8665-db36c56b34d6} <- Manufacturer + Family + ProductName + ProductSku {2b9277cd-85b1-51ee-9a38-d477632532da} <- Manufacturer + Family + ProductName {6e01222b-b2aa-531e-b95f-0e4b2a063364} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {93055898-8c85-50e7-adde-8115f194579a} <- Manufacturer + ProductSku {b3e5b59d-84ae-597d-9222-8a4d48480bc3} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {4f73f73b-e639-5353-bbf7-d851e48f18fc} <- Manufacturer + ProductName {68822228-a3e0-5b12-942d-9408751405d1} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {41b0b5d7-ad12-5d86-9a3d-826f9b20adcc} <- Manufacturer + Family {a26f8d6d-d9ab-5705-939a-aec8fed37cd4} <- Manufacturer + EnclosureKind {cb846e91-7a9f-564f-8f33-6cf5bc04a5b8} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {85d38fda-fc0e-5c6f-808f-076984ae7978} <- Manufacturer Extra Hardware IDs ------------------ {683e4579-8440-5bc1-89ac-dfcd7c25b307} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {fb7493ec-9634-5c5a-9f26-69cbf9b92460} <- Manufacturer + Family + ProductName + BiosVendor {36cb5c6e-fb91-55e9-8077-e004f2b1ddad} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e80100-dell-xps13-9345.txt000066400000000000000000000035171504315023600207720ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Dell Inc. BiosVersion: 2.0.0 BiosMajorRelease: 2 BiosMinorRelease: 0 FirmwareMajorRelease: ff FirmwareMinorRelease: ff Manufacturer: Dell Inc. Family: XPS ProductName: XPS 13 9345 ProductSku: C69 EnclosureKind: a BaseboardManufacturer: Dell Inc. BaseboardProduct: DXPNM Hardware IDs ------------ {eedeb5d9-1a0e-56e6-9137-eb6a723e58d1} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {1eb87d70-2f37-5f18-85de-30e46c17d540} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {1d1baf60-e2f3-5821-9d98-19a131bf8d93} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {7c7c2920-cb59-56ad-bc8a-939e803b0192} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {940c6349-f0a5-54ba-8deb-10e709e0b76c} <- Manufacturer + Family + ProductName + ProductSku {3b9a1d76-f2e8-52e8-84de-14c5942b3d41} <- Manufacturer + Family + ProductName {3c2649a7-2275-5130-a0c4-cc5f9809a2c1} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {36e8dd88-512d-5a74-86a4-039333f9e15a} <- Manufacturer + ProductSku {e656b5f2-69c3-55da-bf22-4dd58d5f6d4f} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {bc685cec-e979-5cb9-bf02-e15586c7cb4b} <- Manufacturer + ProductName {81972cb8-6fc7-5e08-b140-b0063ed4fefa} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {61178075-a8fd-563c-9045-44227d8c121f} <- Manufacturer + Family {5c163113-9296-5c8d-a92d-ae04eb59a0f7} <- Manufacturer + EnclosureKind {1302793c-52b1-5354-b1cf-f2cd9206c157} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {85d38fda-fc0e-5c6f-808f-076984ae7978} <- Manufacturer ubustub-1/hwids/txt/x1e80100-hp-omnibook-x14.txt000066400000000000000000000034241504315023600213250ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Insyde BiosVersion: F.09 Manufacturer: HP Family: 103C_5335M8 HP OmniBook X ProductName: HP OmniBook X Laptop 14-fe0xxx ProductSku: A3NY2EA#ABD EnclosureKind: 10 BaseboardManufacturer: HP BaseboardProduct: 8CBE Hardware IDs ------------ not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown not available as 'BiosMajorRelease' unknown {045dfd0f-068b-5e57-86bd-f41b4b906006} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {ca5dab4f-a301-53c6-b753-c2db56172e0a} <- Manufacturer + Family + ProductName + ProductSku {811126e6-4aee-5f9e-827d-d0f12f6a6f00} <- Manufacturer + Family + ProductName {6a4511bc-0a3b-5b10-9c8b-dbcb834ecd83} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {abb2ffec-2acd-5750-8dfd-c3845fd4bf2a} <- Manufacturer + ProductSku {1a192aee-2cfd-5ab5-95f9-8093218a48ef} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {eaab52c6-ed22-5e1b-b788-fc5a0531291d} <- Manufacturer + ProductName {848aeb1d-302b-5b6b-9109-0f4632535915} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {5d43face-6ba8-5d41-8914-12f3410bbcf9} <- Manufacturer + Family {4c84c882-b54c-58d5-b412-26bcdf254c3e} <- Manufacturer + EnclosureKind {2ae478e9-ef65-5485-bb06-a233136e53c7} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {93f84748-c854-5d6b-b78a-13c2361e0758} <- Manufacturer Extra Hardware IDs ------------------ {54500b82-f7ae-592d-ae68-8c8e362a1475} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {68d24be5-01b6-5d88-83fb-df2bcfa879aa} <- Manufacturer + Family + ProductName + BiosVendor {ad0b7f58-06f2-50b9-856b-343f54261425} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1e80100-lenovo-yoga-slim7x.txt000066400000000000000000000036011504315023600221460ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: LENOVO BiosVersion: NHCN36WW BiosMajorRelease: 1 BiosMinorRelease: 36 FirmwareMajorRelease: 01 FirmwareMinorRelease: 35 Manufacturer: LENOVO Family: Yoga Slim 7 14Q8X9 ProductName: 83ED ProductSku: LENOVO_MT_83ED_BU_idea_FM_Yoga Slim 7 14Q8X9 EnclosureKind: a BaseboardManufacturer: LENOVO BaseboardProduct: LNVNB161216 Hardware IDs ------------ {3fb1e5ba-05cd-5153-ad64-1d8bc6dc7a1b} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {d99f6cb2-4a96-5e4a-8e29-19d52dfc2870} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {6d53c38f-6adb-578b-a418-2abda4d8485d} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {8073dbed-501f-5f5e-a619-4cdd9c00e865} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {d27cf20e-e185-578e-bd46-f4cc3a718bb2} <- Manufacturer + Family + ProductName + ProductSku {8477f828-512b-56cf-af55-c711a6831551} <- Manufacturer + Family + ProductName {f7f92b85-ff01-5e93-a453-c7f91029aa55} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {0700776d-0de7-5ea7-b9bf-77e0454d35e1} <- Manufacturer + ProductSku {ee39b629-4187-5ff7-84c0-e354555562cd} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {fdb12a4f-1e8b-524e-97b5-feef23a8a8da} <- Manufacturer + ProductName {63429d43-c970-570d-aaa7-54300924e0c5} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {8f143f12-40dc-5801-8e61-08a88cd68c1e} <- Manufacturer + Family {e093d715-70f7-51f4-b6c8-b4a7e31def85} <- Manufacturer + EnclosureKind {71d86d4d-02f8-5566-a7a1-529cef184b7e} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {6de5d951-d755-576b-bd09-c5cf66b27234} <- Manufacturer ubustub-1/hwids/txt/x1e80100-microsoft-denali.txt000066400000000000000000000044031504315023600217260ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Microsoft Corporation BiosVersion: 175.77.235 BiosMajorRelease: 255 BiosMinorRelease: 255 FirmwareMajorRelease: ff FirmwareMinorRelease: ff Manufacturer: Microsoft Corporation Family: Surface ProductName: Microsoft Surface Pro, 11th Edition ProductSku: Surface_Pro_11th_Edition_2076 EnclosureKind: 9 BaseboardManufacturer: Microsoft Corporation BaseboardProduct: Microsoft Surface Pro, 11th Edition Hardware IDs ------------ {66f9d954-5c66-5577-b3e4-e3f14f87d2ff} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {5a384f15-464d-5da8-9311-a2c021759afc} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {14b96570-4bc4-541a-9aef-1b7e2b61d7cd} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {aca467c0-5fc2-59ad-8ed5-1b7a0988d11c} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {95971fb3-d478-591f-9ea3-eb0af0d1dfb5} <- Manufacturer + Family + ProductName + ProductSku {c9c14db9-2b61-597a-a4ba-84397fe75f63} <- Manufacturer + Family + ProductName {7cef06f5-e7e6-56d7-b123-a6d640a5d302} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {48b86a5e-1955-5799-9577-150f9e1a69e4} <- Manufacturer + ProductSku {06128fee-87dc-50f6-8a3f-97cd9a6d8bf6} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {84b2e1d1-e695-5f41-8c41-cf1f059c616a} <- Manufacturer + ProductName {16a47337-1f8b-5bd3-b3bd-8e50b31cb1c9} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {ca2e5189-1d32-509f-88a0-d4ebcc721899} <- Manufacturer + Family {aca387a9-183e-5da9-8f9d-f460c3f50f54} <- Manufacturer + EnclosureKind {fdef4ae0-6bfb-5706-8aae-a565639505f5} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {cc0aea32-ad2c-5013-8bed-cede6be8c9f4} <- Manufacturer Extra Hardware IDs ------------------ {01bf1e61-d2e0-518b-bb46-eb4d1f2b1af1} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {584a5084-15f2-5d20-917b-57f299e61f7e} <- Manufacturer + Family + ProductName + BiosVendor {9914cecc-aab7-570e-8fce-e86009ea6bbb} <- Manufacturer + BiosVendor ubustub-1/hwids/txt/x1p42100-asus-zenbook-a14.txt000066400000000000000000000043021504315023600215010ustar00rootroot00000000000000Computer Information -------------------- BiosVendor: Insyde BiosVersion: UX3407QA.305 BiosMajorRelease: 3 BiosMinorRelease: 5 FirmwareMajorRelease: 03 FirmwareMinorRelease: 0b Manufacturer: ASUSTeK COMPUTER INC. Family: ASUS Zenbook A14 ProductName: ASUS Zenbook A14 UX3407QA_UX3407QA ProductSku: EnclosureKind: a BaseboardManufacturer: ASUSTeK COMPUTER INC. BaseboardProduct: UX3407QA Hardware IDs ------------ {c6d100b1-9de7-5636-a3cc-f28fa46fb926} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {85f50d27-f4cb-54df-9aae-f6f09700b132} <- Manufacturer + Family + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {8a72a2ea-3971-55e3-b982-cb6b82868f0e} <- Manufacturer + ProductName + BiosVendor + BiosVersion + BiosMajorRelease + BiosMinorRelease {a034eff6-2891-5de0-b0db-9c5ff350b968} <- Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct {a5b5becc-2a55-5017-b159-087f3846da26} <- Manufacturer + Family + ProductName + ProductSku {59793319-4344-5755-9194-17f29f030d5d} <- Manufacturer + Family + ProductName {14643426-35fa-5a20-bc31-3b6095d2b451} <- Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct {24652d54-00f4-59ae-96fb-f7adbfa4a939} <- Manufacturer + ProductSku {a8425d85-573a-56f8-9d9d-98a196d712fa} <- Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct {7e6d3df4-bf5f-59ab-ad7b-e00677c0ae5a} <- Manufacturer + ProductName {00bc5418-646d-5bab-b772-4efb06f4e7f1} <- Manufacturer + Family + BaseboardManufacturer + BaseboardProduct {c5647aaf-bd0a-5863-bdda-49afd00c5329} <- Manufacturer + Family {665276be-80c5-5e5d-929f-fa85d18e2d50} <- Manufacturer + EnclosureKind {7c5098e1-fa78-597c-a6ba-8b69ccc1cf75} <- Manufacturer + BaseboardManufacturer + BaseboardProduct {65605ed1-09e2-57aa-bd0f-a26c1d35433f} <- Manufacturer Extra Hardware IDs ------------------ {3ca4e2d9-50df-51a5-a87f-4636d425e97d} <- Manufacturer + Family + ProductName + ProductSku + BiosVendor {0b8b84da-462b-5620-bdb5-70272e0ddd94} <- Manufacturer + Family + ProductName + BiosVendor {9d1b57fb-8282-5287-bd50-3c93d43921fa} <- Manufacturer + BiosVendor ubustub-1/include/000077500000000000000000000000001504315023600143275ustar00rootroot00000000000000ubustub-1/include/alloc-util.h000066400000000000000000000240201504315023600165430ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include #include "forward.h" #include "memory-util.h" #if HAS_FEATURE_MEMORY_SANITIZER # include #endif /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */ #define ALLOCA_MAX (4U*1024U*1024U) #define new(t, n) ((t*) malloc_multiply(n, sizeof(t))) #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t))) #define alloca_safe(n) \ ({ \ size_t _nn_ = (n); \ assert(_nn_ <= ALLOCA_MAX); \ alloca(_nn_ == 0 ? 1 : _nn_); \ }) \ #define newa(t, n) \ ({ \ size_t _n_ = (n); \ assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t))); \ (t*) alloca_safe(_n_); \ }) #define newa0(t, n) \ ({ \ size_t _n_ = (n); \ assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t))); \ (t*) alloca0(_n_); \ }) #define newdup(t, p, n) ((t*) memdup_multiply(p, n, sizeof(t))) #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, n, sizeof(t))) #define malloc0(n) (calloc(1, (n) ?: 1)) #define free_and_replace(a, b) \ free_and_replace_full(a, b, free) void* memdup(const void *p, size_t l) _alloc_(2); void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */ #define memdupa(p, l) \ ({ \ void *_q_; \ size_t _l_ = l; \ _q_ = alloca_safe(_l_); \ memcpy_safe(_q_, p, _l_); \ }) #define memdupa_suffix0(p, l) \ ({ \ void *_q_; \ size_t _l_ = l; \ _q_ = alloca_safe(_l_ + 1); \ ((uint8_t*) _q_)[_l_] = 0; \ memcpy_safe(_q_, p, _l_); \ }) static inline void unsetp(void *p) { /* A trivial "destructor" that can be used in cases where we want to * unset a pointer from a _cleanup_ function. */ *(void**)p = NULL; } static inline void freep(void *p) { *(void**)p = mfree(*(void**) p); } #define _cleanup_free_ _cleanup_(freep) static inline bool size_multiply_overflow(size_t size, size_t need) { return _unlikely_(need != 0 && size > (SIZE_MAX / need)); } _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t need, size_t size) { if (size_multiply_overflow(size, need)) return NULL; return malloc(size * need ?: 1); } _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t need, size_t size) { if (size_multiply_overflow(size, need)) return NULL; return memdup(p, size * need); } /* Note that we can't decorate this function with _alloc_() since the returned memory area is one byte larger * than the product of its parameters. */ static inline void *memdup_suffix0_multiply(const void *p, size_t need, size_t size) { if (size_multiply_overflow(size, need)) return NULL; return memdup_suffix0(p, size * need); } static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { size_t m; /* Round up allocation sizes a bit to some reasonable, likely larger value. This is supposed to be * used for cases which are likely called in an allocation loop of some form, i.e. that repetitively * grow stuff, for example strv_extend() and suchlike. * * Note the difference to GREEDY_REALLOC() here, as this helper operates on a single size value only, * and rounds up to next multiple of 2, needing no further counter. * * Note the benefits of direct ALIGN_POWER2() usage: type-safety for size_t, sane handling for very * small (i.e. <= 2) and safe handling for very large (i.e. > SSIZE_MAX) values. */ if (l <= 2) return 2; /* Never allocate less than 2 of something. */ m = ALIGN_POWER2(l); if (m == 0) /* overflow? */ return l; return m; } void* greedy_realloc(void **p, size_t need, size_t size); void* greedy_realloc0(void **p, size_t need, size_t size); void* greedy_realloc_append(void **p, size_t *n_p, const void *from, size_t n_from, size_t size); #define GREEDY_REALLOC(array, need) \ greedy_realloc((void**) &(array), (need), sizeof((array)[0])) #define GREEDY_REALLOC0(array, need) \ greedy_realloc0((void**) &(array), (need), sizeof((array)[0])) #define GREEDY_REALLOC_APPEND(array, n_array, from, n_from) \ ({ \ const typeof(*(array)) *_from_ = (from); \ greedy_realloc_append((void**) &(array), &(n_array), _from_, (n_from), sizeof((array)[0])); \ }) #define alloca0(n) \ ({ \ char *_new_; \ size_t _len_ = n; \ _new_ = alloca_safe(_len_); \ memset(_new_, 0, _len_); \ }) /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ #define alloca_align(size, align) \ ({ \ void *_ptr_; \ size_t _mask_ = (align) - 1; \ size_t _size_ = size; \ _ptr_ = alloca_safe(_size_ + _mask_); \ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ }) #define alloca0_align(size, align) \ ({ \ void *_new_; \ size_t _xsize_ = (size); \ _new_ = alloca_align(_xsize_, (align)); \ memset(_new_, 0, _xsize_); \ }) #if HAS_FEATURE_MEMORY_SANITIZER # define msan_unpoison(r, s) __msan_unpoison(r, s) #else # define msan_unpoison(r, s) #endif /* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the * pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute. This must not * be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because * gcc then loses the attributes on the function. * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */ void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_; size_t malloc_sizeof_safe(void **xp); /* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may * return a value larger than the size that was actually allocated. Access to that additional memory is * discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the * compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function * expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the * lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */ #define MALLOC_SIZEOF_SAFE(x) \ malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x))) /* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items * that fit into the specified memory block */ #define MALLOC_ELEMENTSOF(x) \ (__builtin_choose_expr( \ __builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \ VOID_0)) /* Free every element of the array. */ static inline void free_many(void **p, size_t n) { assert(p || n == 0); FOREACH_ARRAY(i, p, n) *i = mfree(*i); } /* Typesafe wrapper for char** rather than void**. Unfortunately C won't implicitly cast this. */ static inline void free_many_charp(char **c, size_t n) { free_many((void**) c, n); } _alloc_(2) static inline void *realloc0(void *p, size_t new_size) { size_t old_size; void *q; /* Like realloc(), but initializes anything appended to zero */ old_size = MALLOC_SIZEOF_SAFE(p); q = realloc(p, new_size); if (!q) return NULL; new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */ if (new_size > old_size) memset((uint8_t*) q + old_size, 0, new_size - old_size); return q; } ubustub-1/include/assert-fundamental.h000066400000000000000000000033701504315023600203000ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "macro-fundamental.h" _noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function); #ifdef NDEBUG #define assert(expr) ({ if (!(expr)) __builtin_unreachable(); }) #define assert_not_reached() __builtin_unreachable() #else #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); }) #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__) #endif #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); }) /* This passes the argument through after (if asserts are enabled) checking that it is not null. */ #define ASSERT_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert) #define ASSERT_SE_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert_se) #define _ASSERT_PTR(expr, var, check) \ ({ \ typeof(expr) var = (expr); \ check(var); \ var; \ }) #define ASSERT_NONNEG(expr) \ ({ \ typeof(expr) _expr_ = (expr), _zero = 0; \ assert(_expr_ >= _zero); \ _expr_; \ }) #define ASSERT_SE_NONNEG(expr) \ ({ \ typeof(expr) _expr_ = (expr), _zero = 0; \ assert_se(_expr_ >= _zero); \ _expr_; \ }) ubustub-1/include/assert-util.h000066400000000000000000000025501504315023600167560ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "assert-fundamental.h" /* IWYU pragma: export */ /* Logging for various assertions */ void log_set_assert_return_is_critical(bool b); bool log_get_assert_return_is_critical(void) _pure_; void log_assert_failed_return(const char *text, const char *file, int line, const char *func); #define assert_log(expr, message) ((_likely_(expr)) \ ? (true) \ : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false)) #define assert_return(expr, r) \ do { \ if (!assert_log(expr, #expr)) \ return (r); \ } while (false) #define assert_return_errno(expr, r, err) \ do { \ if (!assert_log(expr, #expr)) { \ errno = err; \ return (r); \ } \ } while (false) ubustub-1/include/chid.h000066400000000000000000000124011504315023600154050ustar00rootroot00000000000000/* SPDX-License-Identifier: BSD-3-Clause */ #pragma once #include "efi.h" #define CHID_TYPES_MAX 18 /* Any chids starting from EXTRA_CHID_BASE are non-standard and are subject to change and renumeration at any time */ #define EXTRA_CHID_BASE 15 typedef enum ChidSmbiosFields { CHID_SMBIOS_MANUFACTURER, CHID_SMBIOS_FAMILY, CHID_SMBIOS_PRODUCT_NAME, CHID_SMBIOS_PRODUCT_SKU, CHID_SMBIOS_BASEBOARD_MANUFACTURER, CHID_SMBIOS_BASEBOARD_PRODUCT, CHID_SMBIOS_BIOS_VENDOR, CHID_SMBIOS_BIOS_VERSION, CHID_SMBIOS_BIOS_MAJOR, CHID_SMBIOS_BIOS_MINOR, CHID_SMBIOS_ENCLOSURE_TYPE, CHID_EDID_PANEL, _CHID_SMBIOS_FIELDS_MAX, } ChidSmbiosFields; extern const uint32_t chid_smbios_table[CHID_TYPES_MAX]; /* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */ void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]); /* A .hwids PE section consists of a series of 'Device' structures. A 'Device' structure binds a CHID to some * resource, for now only Devicetree blobs. Designed to be extensible to other types of resources, should the * need arise. The series of 'Device' structures is followed by some space for strings that can be referenced * by offset by the Device structures. */ enum { DEVICE_TYPE_DEVICETREE = 0x1, /* A devicetree blob */ DEVICE_TYPE_UEFI_FW = 0x2, /* A firmware blob */ /* Maybe later additional types for: * - CoCo Bring-Your-Own-Firmware * - ACPI DSDT Overrides * - … */ _DEVICE_TYPE_MAX, }; #define DEVICE_SIZE_FROM_DESCRIPTOR(u) ((uint32_t) (u) & UINT32_C(0x0FFFFFFF)) #define DEVICE_TYPE_FROM_DESCRIPTOR(u) ((uint32_t) (u) >> 28) #define DEVICE_MAKE_DESCRIPTOR(type, size) (((uint32_t) (size) | ((uint32_t) type << 28))) #define DEVICE_DESCRIPTOR_DEVICETREE DEVICE_MAKE_DESCRIPTOR(DEVICE_TYPE_DEVICETREE, sizeof(Device)) #define DEVICE_DESCRIPTOR_UEFI_FW DEVICE_MAKE_DESCRIPTOR(DEVICE_TYPE_UEFI_FW, sizeof(Device)) #define DEVICE_DESCRIPTOR_EOL UINT32_C(0) typedef struct Device { uint32_t descriptor; /* The highest four bit encode the type of entry, the other 28 bit encode the * size of the structure. Use the macros above to generate or take apart this * field. */ EFI_GUID chid; union { struct { /* These offsets are relative to the beginning of the .hwids PE section. */ uint32_t name_offset; /* nul-terminated string or 0 if not present */ uint32_t compatible_offset; /* nul-terminated string or 0 if not present */ } devicetree; struct { /* Offsets are relative to the beginning of the .hwids PE section. * They are nul-terminated strings when present or 0 if not present */ uint32_t name_offset; /* name or identifier for the firmware blob */ uint32_t fwid_offset; /* identifier to match a specific uefi firmware blob */ } uefi_fw; /* fields for other descriptor types… */ }; } _packed_ Device; /* Validate some offset, since the structure is API and src/ukify/ukify.py encodes them directly */ assert_cc(offsetof(Device, descriptor) == 0); assert_cc(offsetof(Device, chid) == 4); assert_cc(offsetof(Device, devicetree.name_offset) == 20); assert_cc(offsetof(Device, devicetree.compatible_offset) == 24); assert_cc(offsetof(Device, uefi_fw.name_offset) == 20); assert_cc(offsetof(Device, uefi_fw.fwid_offset) == 24); assert_cc(sizeof(Device) == 28); static inline const char* device_get_name(const void *base, const Device *device) { size_t off = 0; switch (DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor)) { case DEVICE_TYPE_DEVICETREE: off = device->devicetree.name_offset; break; case DEVICE_TYPE_UEFI_FW: off = device->uefi_fw.name_offset; break; default: return NULL; } return off == 0 ? NULL : (const char *) ((const uint8_t *) base + off); } static inline const char* device_get_compatible(const void *base, const Device *device) { size_t off = 0; switch (DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor)) { case DEVICE_TYPE_DEVICETREE: off = device->devicetree.compatible_offset; break; default: return NULL; } return off == 0 ? NULL : (const char *) ((const uint8_t *) base + off); } static inline const char* device_get_fwid(const void *base, const Device *device) { size_t off = 0; switch (DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor)) { case DEVICE_TYPE_UEFI_FW: off = device->uefi_fw.fwid_offset; break; default: return NULL; } return off == 0 ? NULL : (const char *) ((const uint8_t *) base + off); } EFI_STATUS chid_match(const void *chids_buffer, size_t chids_length, uint32_t match_type, const Device **ret_device); ubustub-1/include/cleanup-fundamental.h000066400000000000000000000064031504315023600204260ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "assert-fundamental.h" /* A wrapper for 'func' to return void. * Only useful when a void-returning function is required by some API. */ #define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ static inline void name(type *p) { \ func(p); \ } /* When func() returns the void value (NULL, -1, …) of the appropriate type */ #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ *p = func(*p); \ } /* When func() doesn't return the appropriate type, set variable to empty afterwards. * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */ #define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \ static inline void func##p(type *p) { \ if (*p != (empty)) { \ DISABLE_WARNING_ADDRESS; \ assert(func); \ REENABLE_WARNING; \ func(*p); \ *p = (empty); \ } \ } /* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */ #define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \ static inline void func##p(type *p) { \ if (*p != (empty)) { \ func(*p); \ *p = (empty); \ } \ } typedef void (*free_array_func_t)(void *p, size_t n); /* An automatic _cleanup_-like logic for destroy arrays (i.e. pointers + size) when leaving scope */ typedef struct ArrayCleanup { void **parray; size_t *pn; free_array_func_t pfunc; } ArrayCleanup; static inline void array_cleanup(const ArrayCleanup *c) { assert(c); assert(!c->parray == !c->pn); if (!c->parray) return; if (*c->parray) { assert(c->pfunc); c->pfunc(*c->parray, *c->pn); *c->parray = NULL; } *c->pn = 0; } #define CLEANUP_ARRAY(array, n, func) \ _cleanup_(array_cleanup) _unused_ const ArrayCleanup CONCATENATE(_cleanup_array_, UNIQ) = { \ .parray = (void**) &(array), \ .pn = &(n), \ .pfunc = (free_array_func_t) ({ \ void (*_f)(typeof(array[0]) *a, size_t b) = func; \ _f; \ }), \ } ubustub-1/include/cleanup-util.h000066400000000000000000000076651504315023600171200ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "cleanup-fundamental.h" /* IWYU pragma: export */ typedef void (*free_func_t)(void *p); typedef void* (*mfree_func_t)(void *p); #define free_and_replace_full(a, b, free_func) \ ({ \ typeof(a)* _a = &(a); \ typeof(b)* _b = &(b); \ free_func(*_a); \ *_a = *_b; \ *_b = NULL; \ 0; \ }) /* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is * increased. */ #define unref_and_replace_full(a, b, ref_func, unref_func) \ ({ \ typeof(a)* _a = &(a); \ typeof(b) _b = ref_func(b); \ unref_func(*_a); \ *_a = _b; \ 0; \ }) #define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \ scope type *name##_ref(type *p) { \ if (!p) \ return NULL; \ \ /* For type check. */ \ unsigned *q = &p->n_ref; \ assert(*q > 0); \ assert_se(*q < UINT_MAX); \ \ (*q)++; \ return p; \ } #define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \ scope type *name##_unref(type *p) { \ if (!p) \ return NULL; \ \ assert(p->n_ref > 0); \ p->n_ref--; \ if (p->n_ref > 0) \ return NULL; \ \ return free_func(p); \ } #define DEFINE_TRIVIAL_REF_FUNC(type, name) \ _DEFINE_TRIVIAL_REF_FUNC(type, name,) #define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \ _DEFINE_TRIVIAL_REF_FUNC(type, name, static) #define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \ _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_) #define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,) #define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static) #define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \ _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_) #define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ DEFINE_TRIVIAL_REF_FUNC(type, name); \ DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func); #define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \ DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func); #define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \ DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func); ubustub-1/include/console.h000066400000000000000000000032351504315023600161450ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "proto/simple-text-io.h" enum { EFI_SHIFT_PRESSED = EFI_RIGHT_SHIFT_PRESSED|EFI_LEFT_SHIFT_PRESSED, EFI_CONTROL_PRESSED = EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED, EFI_ALT_PRESSED = EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED, EFI_LOGO_PRESSED = EFI_RIGHT_LOGO_PRESSED|EFI_LEFT_LOGO_PRESSED, }; #define KEYPRESS(keys, scan, uni) ((((uint64_t)keys) << 32) | (((uint64_t)scan) << 16) | (uni)) #define KEYCHAR(k) ((char16_t)(k)) #define CHAR_CTRL(c) ((c) - 'a' + 1) enum { /* Console mode is a int32_t in EFI. We use int64_t to make room for our special values. */ CONSOLE_MODE_RANGE_MIN = 0, CONSOLE_MODE_RANGE_MAX = INT32_MAX, /* This is just the theoretical limit. */ CONSOLE_MODE_INVALID = -1, /* UEFI uses -1 if the device is not in a valid text mode. */ CONSOLE_MODE_80_25 = 0, /* 80x25 is required by UEFI spec. */ CONSOLE_MODE_80_50 = 1, /* 80x50 may be supported. */ CONSOLE_MODE_FIRMWARE_FIRST = 2, /* First custom mode, if supported. */ /* These are our own mode values that map to concrete values at runtime. */ CONSOLE_MODE_KEEP = CONSOLE_MODE_RANGE_MAX + 1LL, CONSOLE_MODE_NEXT, CONSOLE_MODE_AUTO, CONSOLE_MODE_FIRMWARE_MAX, /* 'max' in config. */ }; EFI_STATUS console_key_read(uint64_t *ret_key, uint64_t timeout_usec); EFI_STATUS console_set_mode(int64_t mode); EFI_STATUS console_query_mode(size_t *x_max, size_t *y_max); EFI_STATUS query_screen_resolution(uint32_t *ret_width, uint32_t *ret_height); ubustub-1/include/device-path-util.h000066400000000000000000000025571504315023600176550ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "proto/device-path.h" EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DEVICE_PATH **ret_dp); EFI_STATUS make_url_device_path(const char16_t *url, EFI_DEVICE_PATH **ret); EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret); bool device_path_startswith(const EFI_DEVICE_PATH *dp, const EFI_DEVICE_PATH *start); EFI_DEVICE_PATH *device_path_replace_node( const EFI_DEVICE_PATH *path, const EFI_DEVICE_PATH *node, const EFI_DEVICE_PATH *new_node); static inline EFI_DEVICE_PATH *device_path_next_node(const EFI_DEVICE_PATH *dp) { assert(dp); return (EFI_DEVICE_PATH *) ((uint8_t *) dp + dp->Length); } static inline bool device_path_is_end(const EFI_DEVICE_PATH *dp) { assert(dp); return dp->Type == END_DEVICE_PATH_TYPE && dp->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE; } #define DEVICE_PATH_END_NODE \ (EFI_DEVICE_PATH) { \ .Type = END_DEVICE_PATH_TYPE, \ .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, \ .Length = sizeof(EFI_DEVICE_PATH) \ } size_t device_path_size(const EFI_DEVICE_PATH *dp); EFI_DEVICE_PATH *device_path_dup(const EFI_DEVICE_PATH *dp); ubustub-1/include/devicetree.h000066400000000000000000000023551504315023600166240ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" struct devicetree_state { EFI_PHYSICAL_ADDRESS addr; size_t pages; void *orig; }; enum { FDT_BEGIN_NODE = 1, FDT_END_NODE = 2, FDT_PROP = 3, FDT_NOP = 4, FDT_END = 9, }; typedef struct FdtHeader { uint32_t magic; uint32_t total_size; uint32_t off_dt_struct; uint32_t off_dt_strings; uint32_t off_mem_rsv_map; uint32_t version; uint32_t last_comp_version; uint32_t boot_cpuid_phys; uint32_t size_dt_strings; uint32_t size_dt_struct; } FdtHeader; bool firmware_devicetree_exists(void); const char* devicetree_get_compatible(const void *dtb); EFI_STATUS devicetree_match(const void *uki_dtb, size_t uki_dtb_length); EFI_STATUS devicetree_match_by_compatible(const void *uki_dtb, size_t uki_dtb_length, const char *compat); EFI_STATUS devicetree_install(struct devicetree_state *state, EFI_FILE *root_dir, char16_t *name); EFI_STATUS devicetree_install_from_memory( struct devicetree_state *state, const void *dtb_buffer, size_t dtb_length); void devicetree_cleanup(struct devicetree_state *state); ubustub-1/include/edid.h000066400000000000000000000020601504315023600154030ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi-string.h" #include "util.h" #include "efi.h" #include "macro-fundamental.h" /* EDID structure, version 1.4 */ typedef struct EdidHeader { uint8_t pattern[8]; /* fixed pattern */ uint16_t manufacturer_id; /* big-endian 3-letter code */ uint16_t manufacturer_product_code; /* little-endian */ uint32_t serial_number; /* little-endian */ uint8_t week_of_manufacture; /* week or model year flag (0xFF) */ uint8_t year_of_manufacture; /* year or model if flag is set (0 is 1990) */ uint8_t edid_version; /* 0x01 for 1.3 and 1.4 */ uint8_t edid_revision; /* 0x03 for 1.3, 0x04 for 1.4 */ } _packed_ EdidHeader; int edid_parse_blob(const void *blob, size_t blob_size, EdidHeader *ret_header); int edid_get_panel_id(const EdidHeader *edid_header, char16_t ret_panel[static 8]); EFI_STATUS edid_get_discovered_panel_id(char16_t **ret_panel); ubustub-1/include/efi-efivars.h000066400000000000000000000032611504315023600167020ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "efivars-fundamental.h" /* IWYU pragma: export */ /* * Allocated random UUID, intended to be shared across tools that implement * the (ESP)\loader\entries\-.conf convention and the * associated EFI variables. */ #define LOADER_GUID \ { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } } EFI_STATUS efivar_set_str16(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags); EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const char16_t *name, const void *buf, size_t size, uint32_t flags); EFI_STATUS efivar_set_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t i, uint32_t flags); EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t value, uint32_t flags); EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t value, uint32_t flags); EFI_STATUS efivar_unset(const EFI_GUID *vendor, const char16_t *name, uint32_t flags); EFI_STATUS efivar_get_str16(const EFI_GUID *vendor, const char16_t *name, char16_t **ret); EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const char16_t *name, void **ret_data, size_t *ret_size); EFI_STATUS efivar_get_uint64_str16(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret); EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, uint32_t *ret); EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret); EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret); uint64_t get_os_indications_supported(void); ubustub-1/include/efi-firmware.h000066400000000000000000000024161504315023600170600ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define FWHEADERMAGIC (UINT32_C(0xfeeddead)) /* The structure of the efifw UKI blob is the following: * --------------------------------------------------------- * EfiFw header|fwid|payload| reserved for future attributes * --------------------------------------------------------- * The base header defines the length of full header, fwid and payload. * The fwid is a NUL terminated string. * The payload contains the actual efi firmware. */ typedef struct EfiFwHeader { uint32_t magic; /* magic number that defines Efifw */ uint32_t header_len; /* total length of header including all attributes */ uint32_t fwid_len; /* length including the NUL terminator */ uint32_t payload_len; /* actual length of the efi firmware binary image */ /* The header might be extended in the future to add additional * parameters. header_len will increase to indicate presence of these * additional attributes. */ /* next comes payload which is fwid and efi firmware binary blob */ uint8_t payload[] _alignas_(uint64_t); } EfiFwHeader; EFI_STATUS efi_firmware_match_by_fwid(const void *blob, size_t blob_len, const char *fwid); ubustub-1/include/efi-fundamental.h000066400000000000000000000043711504315023600175440ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include /* Matches EFI API definition of the same structure for userspace */ typedef struct { uint32_t Data1; uint16_t Data2; uint16_t Data3; uint8_t Data4[8]; } EFI_GUID; typedef struct { EFI_GUID SignatureOwner; uint8_t SignatureData[]; } EFI_SIGNATURE_DATA; typedef struct { EFI_GUID SignatureType; uint32_t SignatureListSize; uint32_t SignatureHeaderSize; uint32_t SignatureSize; EFI_SIGNATURE_DATA Signatures[]; } EFI_SIGNATURE_LIST; typedef struct { uint32_t dwLength; uint16_t wRevision; uint16_t wCertificateType; } WIN_CERTIFICATE_HEADER; typedef struct { WIN_CERTIFICATE_HEADER Hdr; EFI_GUID CertType; uint8_t CertData[]; } WIN_CERTIFICATE_UEFI_GUID; typedef struct { uint16_t Year; uint8_t Month; uint8_t Day; uint8_t Hour; uint8_t Minute; uint8_t Second; uint8_t Pad1; uint32_t Nanosecond; int16_t TimeZone; uint8_t Daylight; uint8_t Pad2; } EFI_TIME; typedef struct { EFI_TIME TimeStamp; WIN_CERTIFICATE_UEFI_GUID AuthInfo; } EFI_VARIABLE_AUTHENTICATION_2; #define GUID_DEF(d1, d2, d3, d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8) \ { d1, d2, d3, { d4_1, d4_2, d4_3, d4_4, d4_5, d4_6, d4_7, d4_8 } } /* Creates a EFI_GUID pointer suitable for EFI APIs. Use of const allows the compiler to merge multiple * uses (although, currently compilers do that regardless). Most EFI APIs declare their EFI_GUID input * as non-const, but almost all of them are in fact const. */ #define MAKE_GUID_PTR(name) ((EFI_GUID *) &(const EFI_GUID) name##_GUID) #define EFI_GLOBAL_VARIABLE \ GUID_DEF(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) #define EFI_IMAGE_SECURITY_DATABASE_GUID \ GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f) #define EFI_CERT_X509_GUID \ GUID_DEF(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72) #define EFI_CERT_TYPE_PKCS7_GUID \ GUID_DEF(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) ubustub-1/include/efi-log.h000066400000000000000000000035121504315023600160230ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "efi-string.h" #include "proto/simple-text-io.h" #if defined __has_attribute # if __has_attribute(no_stack_protector) # define HAVE_NO_STACK_PROTECTOR_ATTRIBUTE # endif #endif #if defined(HAVE_NO_STACK_PROTECTOR_ATTRIBUTE) && \ (defined(__SSP__) || defined(__SSP_ALL__) || \ defined(__SSP_STRONG__) || defined(__SSP_EXPLICIT__)) # define STACK_PROTECTOR_RANDOM 1 __attribute__((no_stack_protector, noinline)) void __stack_chk_guard_init(void); #else # define STACK_PROTECTOR_RANDOM 0 # define __stack_chk_guard_init() #endif extern bool log_isdebug; _noreturn_ void freeze(void); void log_wait(void); _gnu_printf_(3, 4) EFI_STATUS log_internal(EFI_STATUS status, uint8_t text_color, const char *format, ...); #define log_full(status, text_color, format, ...) \ log_internal(status, text_color, "%s:%i@%s: " format, __FILE__, __LINE__, __func__, ##__VA_ARGS__) #define log_debug(...) ({ log_isdebug && log_full(EFI_SUCCESS, EFI_LIGHTGRAY, __VA_ARGS__); }) #define log_info(...) log_full(EFI_SUCCESS, EFI_WHITE, __VA_ARGS__) #define log_warning_status(status, ...) log_full(status, EFI_YELLOW, __VA_ARGS__) #define log_error_status(status, ...) log_full(status, EFI_LIGHTRED, __VA_ARGS__) #define log_error(...) log_full(EFI_INVALID_PARAMETER, EFI_LIGHTRED, __VA_ARGS__) #define log_oom() log_full(EFI_OUT_OF_RESOURCES, EFI_LIGHTRED, "Out of memory.") /* Debugging helper — please keep this around, even if not used */ #define log_hexdump(prefix, data, size) \ ({ \ _cleanup_free_ char16_t *hex = hexdump(data, size); \ log_debug("%ls[%zu]: %ls", prefix, size, hex); \ }) ubustub-1/include/efi-string-table.h000066400000000000000000000011641504315023600176360ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "macro-fundamental.h" #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ scope const char* name##_to_string(type i) { \ assert(i >= 0 && i < (type) ELEMENTSOF(name##_table)); \ return name##_table[i]; \ } #define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) ubustub-1/include/efi-string.h000066400000000000000000000134441504315023600165550ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" size_t strnlen8(const char *s, size_t n); size_t strnlen16(const char16_t *s, size_t n); static inline size_t strlen8(const char *s) { return strnlen8(s, SIZE_MAX); } static inline size_t strlen16(const char16_t *s) { return strnlen16(s, SIZE_MAX); } static inline size_t strsize8(const char *s) { return s ? (strlen8(s) + 1) * sizeof(*s) : 0; } static inline size_t strsize16(const char16_t *s) { return s ? (strlen16(s) + 1) * sizeof(*s) : 0; } char* strtolower8(char *s); char16_t* strtolower16(char16_t *s); int strncmp8(const char *s1, const char *s2, size_t n); int strncmp16(const char16_t *s1, const char16_t *s2, size_t n); int strncasecmp8(const char *s1, const char *s2, size_t n); int strncasecmp16(const char16_t *s1, const char16_t *s2, size_t n); static inline int strcmp8(const char *s1, const char *s2) { return strncmp8(s1, s2, SIZE_MAX); } static inline int strcmp16(const char16_t *s1, const char16_t *s2) { return strncmp16(s1, s2, SIZE_MAX); } static inline int strcasecmp8(const char *s1, const char *s2) { return strncasecmp8(s1, s2, SIZE_MAX); } static inline int strcasecmp16(const char16_t *s1, const char16_t *s2) { return strncasecmp16(s1, s2, SIZE_MAX); } static inline bool strneq8(const char *s1, const char *s2, size_t n) { return strncmp8(s1, s2, n) == 0; } static inline bool strneq16(const char16_t *s1, const char16_t *s2, size_t n) { return strncmp16(s1, s2, n) == 0; } static inline bool streq8(const char *s1, const char *s2) { return strcmp8(s1, s2) == 0; } static inline bool streq16(const char16_t *s1, const char16_t *s2) { return strcmp16(s1, s2) == 0; } static inline int strncaseeq8(const char *s1, const char *s2, size_t n) { return strncasecmp8(s1, s2, n) == 0; } static inline int strncaseeq16(const char16_t *s1, const char16_t *s2, size_t n) { return strncasecmp16(s1, s2, n) == 0; } static inline bool strcaseeq8(const char *s1, const char *s2) { return strcasecmp8(s1, s2) == 0; } static inline bool strcaseeq16(const char16_t *s1, const char16_t *s2) { return strcasecmp16(s1, s2) == 0; } char* strcpy8(char * restrict dest, const char * restrict src); char16_t *strcpy16(char16_t * restrict dest, const char16_t * restrict src); char* strchr8(const char *s, char c); char16_t *strchr16(const char16_t *s, char16_t c); char* xstrndup8(const char *s, size_t n); char16_t *xstrndup16(const char16_t *s, size_t n); static inline char* xstrdup8(const char *s) { return xstrndup8(s, SIZE_MAX); } static inline char16_t *xstrdup16(const char16_t *s) { return xstrndup16(s, SIZE_MAX); } char16_t *xstrn8_to_16(const char *str8, size_t n); static inline char16_t *xstr8_to_16(const char *str8) { return xstrn8_to_16(str8, SIZE_MAX); } char *xstrn16_to_ascii(const char16_t *str16, size_t n); static inline char *xstr16_to_ascii(const char16_t *str16) { return xstrn16_to_ascii(str16, SIZE_MAX); } char* startswith8(const char *s, const char *prefix); size_t strspn16(const char16_t *p, const char16_t *good); size_t strcspn16(const char16_t *p, const char16_t *bad); bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack); bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail); bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tail); bool parse_boolean(const char *v, bool *ret); char* line_get_key_value(char *s, const char *sep, size_t *pos, char **ret_key, char **ret_value); char16_t *hexdump(const void *data, size_t size); #ifdef __clang__ # define _gnu_printf_(a, b) _printf_(a, b) #else # define _gnu_printf_(a, b) __attribute__((format(gnu_printf, a, b))) #endif _gnu_printf_(2, 3) void printf_status(EFI_STATUS status, const char *format, ...); _gnu_printf_(2, 0) void vprintf_status(EFI_STATUS status, const char *format, va_list ap); _gnu_printf_(2, 3) _warn_unused_result_ char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...); _gnu_printf_(2, 0) _warn_unused_result_ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap); #define printf(...) printf_status(EFI_SUCCESS, __VA_ARGS__) #define xasprintf(...) xasprintf_status(EFI_SUCCESS, __VA_ARGS__) /* inttypes.h is provided by libc instead of the compiler and is not supposed to be used in freestanding * environments. We could use clang __*_FMT*__ constants for this, bug gcc does not have them. :( */ #if defined(__ILP32__) || defined(__arm__) || defined(__i386__) # define PRI64_PREFIX "ll" #elif defined(__LP64__) # define PRI64_PREFIX "l" #elif defined(__LLP64__) || (__SIZEOF_LONG__ == 4 && __SIZEOF_POINTER__ == 8) # define PRI64_PREFIX "ll" #else # error Unknown 64-bit data model #endif #define PRIi32 "i" #define PRIu32 "u" #define PRIx32 "x" #define PRIX32 "X" #define PRIiPTR "zi" #define PRIuPTR "zu" #define PRIxPTR "zx" #define PRIXPTR "zX" #define PRIi64 PRI64_PREFIX "i" #define PRIu64 PRI64_PREFIX "u" #define PRIx64 PRI64_PREFIX "x" #define PRIX64 PRI64_PREFIX "X" /* The compiler normally has knowledge about standard functions such as memcmp, but this is not the case when * compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do * optimizations again. Note that we still need to provide implementations as the compiler is free to not * inline its own implementation and instead issue a library call. */ #define memchr __builtin_memchr #define memcmp __builtin_memcmp #define memcpy __builtin_memcpy #define memset __builtin_memset static inline void *mempcpy(void * restrict dest, const void * restrict src, size_t n) { if (!dest || !src || n == 0) return dest; memcpy(dest, src, n); return (uint8_t *) dest + n; } ubustub-1/include/efi.h000066400000000000000000000421371504315023600152520ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /* IWYU pragma: always_keep */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include "assert-fundamental.h" /* IWYU pragma: export */ #include "cleanup-fundamental.h" /* IWYU pragma: export */ #include "efi-fundamental.h" /* IWYU pragma: export */ #include "macro-fundamental.h" /* IWYU pragma: export */ /* uchar.h/wchar.h are not suitable for freestanding environments. */ typedef __WCHAR_TYPE__ wchar_t; typedef __CHAR16_TYPE__ char16_t; typedef __CHAR32_TYPE__ char32_t; /* Let's be paranoid and do some sanity checks. */ assert_cc(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__); assert_cc(__STDC_HOSTED__ == 0); assert_cc(sizeof(bool) == 1); assert_cc(sizeof(uint8_t) == 1); assert_cc(sizeof(uint16_t) == 2); assert_cc(sizeof(uint32_t) == 4); assert_cc(sizeof(uint64_t) == 8); assert_cc(sizeof(wchar_t) == 2); assert_cc(sizeof(char16_t) == 2); assert_cc(sizeof(char32_t) == 4); assert_cc(sizeof(size_t) == sizeof(void *)); assert_cc(sizeof(size_t) == sizeof(uintptr_t)); assert_cc(alignof(bool) == 1); assert_cc(alignof(uint8_t) == 1); assert_cc(alignof(uint16_t) == 2); assert_cc(alignof(uint32_t) == 4); assert_cc(alignof(uint64_t) == 8); assert_cc(alignof(wchar_t) == 2); assert_cc(alignof(char16_t) == 2); assert_cc(alignof(char32_t) == 4); #if defined(__x86_64__) && defined(__ILP32__) # error Building for x64 requires -m64 on x32 ABI. #endif struct iovec; /* We use size_t/ssize_t to represent UEFI UINTN/INTN. */ typedef size_t EFI_STATUS; typedef intptr_t ssize_t; typedef void* EFI_HANDLE; typedef void* EFI_EVENT; typedef size_t EFI_TPL; typedef uint64_t EFI_LBA; typedef uint64_t EFI_PHYSICAL_ADDRESS; #if defined(__x86_64__) && !defined(__ILP32__) # define EFIAPI __attribute__((ms_abi)) #else # define EFIAPI #endif #if __SIZEOF_POINTER__ == 8 # define EFI_ERROR_MASK 0x8000000000000000ULL #elif __SIZEOF_POINTER__ == 4 # define EFI_ERROR_MASK 0x80000000ULL #else # error Unsupported pointer size #endif #define EFI_STATUS_IS_ERROR(s) (((s) & EFI_ERROR_MASK) != 0) #define EFIWARN(s) ((EFI_STATUS) s) #define EFIERR(s) ((EFI_STATUS) (s | EFI_ERROR_MASK)) #define EFI_SUCCESS EFIWARN(0) #define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) #define EFI_WARN_DELETE_FAILURE EFIWARN(2) #define EFI_WARN_WRITE_FAILURE EFIWARN(3) #define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) #define EFI_WARN_STALE_DATA EFIWARN(5) #define EFI_WARN_FILE_SYSTEM EFIWARN(6) #define EFI_WARN_RESET_REQUIRED EFIWARN(7) #define EFI_LOAD_ERROR EFIERR(1) #define EFI_INVALID_PARAMETER EFIERR(2) #define EFI_UNSUPPORTED EFIERR(3) #define EFI_BAD_BUFFER_SIZE EFIERR(4) #define EFI_BUFFER_TOO_SMALL EFIERR(5) #define EFI_NOT_READY EFIERR(6) #define EFI_DEVICE_ERROR EFIERR(7) #define EFI_WRITE_PROTECTED EFIERR(8) #define EFI_OUT_OF_RESOURCES EFIERR(9) #define EFI_VOLUME_CORRUPTED EFIERR(10) #define EFI_VOLUME_FULL EFIERR(11) #define EFI_NO_MEDIA EFIERR(12) #define EFI_MEDIA_CHANGED EFIERR(13) #define EFI_NOT_FOUND EFIERR(14) #define EFI_ACCESS_DENIED EFIERR(15) #define EFI_NO_RESPONSE EFIERR(16) #define EFI_NO_MAPPING EFIERR(17) #define EFI_TIMEOUT EFIERR(18) #define EFI_NOT_STARTED EFIERR(19) #define EFI_ALREADY_STARTED EFIERR(20) #define EFI_ABORTED EFIERR(21) #define EFI_ICMP_ERROR EFIERR(22) #define EFI_TFTP_ERROR EFIERR(23) #define EFI_PROTOCOL_ERROR EFIERR(24) #define EFI_INCOMPATIBLE_VERSION EFIERR(25) #define EFI_SECURITY_VIOLATION EFIERR(26) #define EFI_CRC_ERROR EFIERR(27) #define EFI_END_OF_MEDIA EFIERR(28) #define EFI_ERROR_RESERVED_29 EFIERR(29) #define EFI_ERROR_RESERVED_30 EFIERR(30) #define EFI_END_OF_FILE EFIERR(31) #define EFI_INVALID_LANGUAGE EFIERR(32) #define EFI_COMPROMISED_DATA EFIERR(33) #define EFI_IP_ADDRESS_CONFLICT EFIERR(34) #define EFI_HTTP_ERROR EFIERR(35) /* These allow MAKE_GUID_PTR() to work without requiring an extra _GUID in the passed name. We want to * keep the GUID definitions in line with the UEFI spec. */ #define EFI_GLOBAL_VARIABLE_GUID EFI_GLOBAL_VARIABLE #define EFI_FILE_INFO_GUID EFI_FILE_INFO_ID #define EFI_CUSTOM_MODE_ENABLE_GUID \ GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f) #define EFI_SYSTEM_RESOURCE_TABLE_GUID \ GUID_DEF(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) /* EFI System Resource Table (ESRT) Firmware Type Definitions */ #define ESRT_FW_TYPE_UNKNOWN 0x00000000U #define ESRT_FW_TYPE_SYSTEMFIRMWARE 0x00000001U #define ESRT_FW_TYPE_DEVICEFIRMWARE 0x00000002U #define ESRT_FW_TYPE_UEFIDRIVER 0x00000003U #define LAST_ATTEMPT_STATUS_SUCCESS 0x00000000U #define EVT_TIMER 0x80000000U #define EVT_RUNTIME 0x40000000U #define EVT_NOTIFY_WAIT 0x00000100U #define EVT_NOTIFY_SIGNAL 0x00000200U #define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201U #define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202U #define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x01U #define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x02U #define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x04U #define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x08U #define EFI_OPEN_PROTOCOL_BY_DRIVER 0x10U #define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x20U #define EFI_VARIABLE_NON_VOLATILE 0x01U #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x02U #define EFI_VARIABLE_RUNTIME_ACCESS 0x04U #define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x08U #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x10U #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x20U #define EFI_VARIABLE_APPEND_WRITE 0x40U #define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS 0x80U #define EFI_TIME_ADJUST_DAYLIGHT 0x001U #define EFI_TIME_IN_DAYLIGHT 0x002U #define EFI_UNSPECIFIED_TIMEZONE 0x7FFU #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x01U #define EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION 0x02U #define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED 0x04U #define EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED 0x08U #define EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED 0x10U #define EFI_OS_INDICATIONS_START_OS_RECOVERY 0x20U #define EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY 0x40U #define EFI_OS_INDICATIONS_JSON_CONFIG_DATA_REFRESH 0x80U #define EFI_PAGE_SIZE 4096U #define EFI_SIZE_TO_PAGES(s) (((s) + 0xFFFU) >> 12U) /* These are common enough to warrant forward declaration. We also give them a * shorter name for convenience. */ typedef struct EFI_FILE_PROTOCOL EFI_FILE; typedef struct EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH; typedef struct EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL; typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; typedef enum { TimerCancel, TimerPeriodic, TimerRelative, } EFI_TIMER_DELAY; typedef enum { AllocateAnyPages, AllocateMaxAddress, AllocateAddress, MaxAllocateType, } EFI_ALLOCATE_TYPE; typedef enum { EfiReservedMemoryType, EfiLoaderCode, EfiLoaderData, EfiBootServicesCode, EfiBootServicesData, EfiRuntimeServicesCode, EfiRuntimeServicesData, EfiConventionalMemory, EfiUnusableMemory, EfiACPIReclaimMemory, EfiACPIMemoryNVS, EfiMemoryMappedIO, EfiMemoryMappedIOPortSpace, EfiPalCode, EfiPersistentMemory, EfiUnacceptedMemoryType, EfiMaxMemoryType, } EFI_MEMORY_TYPE; typedef enum { AllHandles, ByRegisterNotify, ByProtocol, } EFI_LOCATE_SEARCH_TYPE; typedef enum { EfiResetCold, EfiResetWarm, EfiResetShutdown, EfiResetPlatformSpecific, } EFI_RESET_TYPE; typedef struct { uint32_t Resolution; uint32_t Accuracy; bool SetsToZero; } EFI_TIME_CAPABILITIES; typedef struct { uint64_t Signature; uint32_t Revision; uint32_t HeaderSize; uint32_t CRC32; uint32_t Reserved; } EFI_TABLE_HEADER; typedef struct { EFI_TABLE_HEADER Hdr; void *RaiseTPL; void *RestoreTPL; EFI_STATUS (EFIAPI *AllocatePages)( EFI_ALLOCATE_TYPE Type, EFI_MEMORY_TYPE MemoryType, size_t Pages, EFI_PHYSICAL_ADDRESS *Memory); EFI_STATUS (EFIAPI *FreePages)( EFI_PHYSICAL_ADDRESS Memory, size_t Pages); void *GetMemoryMap; EFI_STATUS (EFIAPI *AllocatePool)( EFI_MEMORY_TYPE PoolType, size_t Size, void **Buffer); EFI_STATUS (EFIAPI *FreePool)(void *Buffer); EFI_STATUS (EFIAPI *CreateEvent)( uint32_t Type, EFI_TPL NotifyTpl, void *NotifyFunction, void *NotifyContext, EFI_EVENT *Event); EFI_STATUS (EFIAPI *SetTimer)( EFI_EVENT Event, EFI_TIMER_DELAY Type, uint64_t TriggerTime); EFI_STATUS (EFIAPI *WaitForEvent)( size_t NumberOfEvents, EFI_EVENT *Event, size_t *Index); void *SignalEvent; EFI_STATUS (EFIAPI *CloseEvent)(EFI_EVENT Event); EFI_STATUS (EFIAPI *CheckEvent)(EFI_EVENT Event); void *InstallProtocolInterface; EFI_STATUS (EFIAPI *ReinstallProtocolInterface)( EFI_HANDLE Handle, EFI_GUID *Protocol, void *OldInterface, void *NewInterface); void *UninstallProtocolInterface; EFI_STATUS (EFIAPI *HandleProtocol)( EFI_HANDLE Handle, EFI_GUID *Protocol, void **Interface); void *Reserved; void *RegisterProtocolNotify; EFI_STATUS (EFIAPI *LocateHandle)( EFI_LOCATE_SEARCH_TYPE SearchType, EFI_GUID *Protocol, void *SearchKey, size_t *BufferSize, EFI_HANDLE *Buffer); EFI_STATUS (EFIAPI *LocateDevicePath)( EFI_GUID *Protocol, EFI_DEVICE_PATH **DevicePath, EFI_HANDLE *Device); EFI_STATUS (EFIAPI *InstallConfigurationTable)( EFI_GUID *Guid, void *Table); EFI_STATUS (EFIAPI *LoadImage)( bool BootPolicy, EFI_HANDLE ParentImageHandle, EFI_DEVICE_PATH *DevicePath, void *SourceBuffer, size_t SourceSize, EFI_HANDLE *ImageHandle); EFI_STATUS (EFIAPI *StartImage)( EFI_HANDLE ImageHandle, size_t *ExitDataSize, char16_t **ExitData); EFI_STATUS (EFIAPI *Exit)( EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus, size_t ExitDataSize, char16_t *ExitData); EFI_STATUS (EFIAPI *UnloadImage)(EFI_HANDLE ImageHandle); void *ExitBootServices; EFI_STATUS (EFIAPI *GetNextMonotonicCount)(uint64_t *Count); EFI_STATUS (EFIAPI *Stall)(size_t Microseconds); EFI_STATUS (EFIAPI *SetWatchdogTimer)( size_t Timeout, uint64_t WatchdogCode, size_t DataSize, char16_t *WatchdogData); EFI_STATUS (EFIAPI *ConnectController)( EFI_HANDLE ControllerHandle, EFI_HANDLE *DriverImageHandle, EFI_DEVICE_PATH *RemainingDevicePath, bool Recursive); EFI_STATUS (EFIAPI *DisconnectController)( EFI_HANDLE ControllerHandle, EFI_HANDLE DriverImageHandle, EFI_HANDLE ChildHandle); EFI_STATUS (EFIAPI *OpenProtocol)( EFI_HANDLE Handle, EFI_GUID *Protocol, void **Interface, EFI_HANDLE AgentHandle, EFI_HANDLE ControllerHandle, uint32_t Attributes); EFI_STATUS (EFIAPI *CloseProtocol)( EFI_HANDLE Handle, EFI_GUID *Protocol, EFI_HANDLE AgentHandle, EFI_HANDLE ControllerHandle); void *OpenProtocolInformation; EFI_STATUS (EFIAPI *ProtocolsPerHandle)( EFI_HANDLE Handle, EFI_GUID ***ProtocolBuffer, size_t *ProtocolBufferCount); EFI_STATUS (EFIAPI *LocateHandleBuffer)( EFI_LOCATE_SEARCH_TYPE SearchType, EFI_GUID *Protocol, void *SearchKey, size_t *NoHandles, EFI_HANDLE **Buffer); EFI_STATUS (EFIAPI *LocateProtocol)( EFI_GUID *Protocol, void *Registration, void **Interface); EFI_STATUS (EFIAPI *InstallMultipleProtocolInterfaces)(EFI_HANDLE *Handle, ...); EFI_STATUS (EFIAPI *UninstallMultipleProtocolInterfaces)(EFI_HANDLE Handle, ...); EFI_STATUS (EFIAPI *CalculateCrc32)( void *Data, size_t DataSize, uint32_t *Crc32); void (EFIAPI *CopyMem)( void *Destination, void *Source, size_t Length); void (EFIAPI *SetMem)( void *Buffer, size_t Size, uint8_t Value); void *CreateEventEx; } EFI_BOOT_SERVICES; typedef struct { EFI_TABLE_HEADER Hdr; EFI_STATUS (EFIAPI *GetTime)( EFI_TIME *Time, EFI_TIME_CAPABILITIES *Capabilities); EFI_STATUS (EFIAPI *SetTime)(EFI_TIME *Time); void *GetWakeupTime; void *SetWakeupTime; void *SetVirtualAddressMap; void *ConvertPointer; EFI_STATUS (EFIAPI *GetVariable)( char16_t *VariableName, EFI_GUID *VendorGuid, uint32_t *Attributes, size_t *DataSize, void *Data); void *GetNextVariableName; EFI_STATUS (EFIAPI *SetVariable)( char16_t *VariableName, EFI_GUID *VendorGuid, uint32_t Attributes, size_t DataSize, void *Data); EFI_STATUS (EFIAPI *GetNextHighMonotonicCount)(uint32_t *HighCount); void (EFIAPI *ResetSystem)( EFI_RESET_TYPE ResetType, EFI_STATUS ResetStatus, size_t DataSize, void *ResetData); void *UpdateCapsule; void *QueryCapsuleCapabilities; void *QueryVariableInfo; } EFI_RUNTIME_SERVICES; typedef struct { EFI_TABLE_HEADER Hdr; char16_t *FirmwareVendor; uint32_t FirmwareRevision; EFI_HANDLE ConsoleInHandle; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; EFI_HANDLE ConsoleOutHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; EFI_HANDLE StandardErrorHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; EFI_RUNTIME_SERVICES *RuntimeServices; EFI_BOOT_SERVICES *BootServices; size_t NumberOfTableEntries; struct { EFI_GUID VendorGuid; void *VendorTable; } *ConfigurationTable; } EFI_SYSTEM_TABLE; typedef struct { EFI_GUID FwClass; uint32_t FwType; uint32_t FwVersion; uint32_t LowestSupportedFwVersion; uint32_t CapsuleFlags; uint32_t LastAttemptVersion; uint32_t LastAttemptStatus; } EFI_SYSTEM_RESOURCE_ENTRY; typedef struct { uint32_t FwResourceCount; uint32_t FwResourceCountMax; uint64_t FwResourceVersion; EFI_SYSTEM_RESOURCE_ENTRY Entries[]; } EFI_SYSTEM_RESOURCE_TABLE; extern EFI_SYSTEM_TABLE *ST; extern EFI_BOOT_SERVICES *BS; extern EFI_RUNTIME_SERVICES *RT; ubustub-1/include/efivars-fundamental.h000066400000000000000000000044241504315023600204370ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #define EINVAL 22 #include "string-util-fundamental.h" /* Features of the loader, i.e. systemd-boot */ #define EFI_LOADER_FEATURE_CONFIG_TIMEOUT (UINT64_C(1) << 0) #define EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT (UINT64_C(1) << 1) #define EFI_LOADER_FEATURE_ENTRY_DEFAULT (UINT64_C(1) << 2) #define EFI_LOADER_FEATURE_ENTRY_ONESHOT (UINT64_C(1) << 3) #define EFI_LOADER_FEATURE_BOOT_COUNTING (UINT64_C(1) << 4) #define EFI_LOADER_FEATURE_XBOOTLDR (UINT64_C(1) << 5) #define EFI_LOADER_FEATURE_RANDOM_SEED (UINT64_C(1) << 6) #define EFI_LOADER_FEATURE_LOAD_DRIVER (UINT64_C(1) << 7) #define EFI_LOADER_FEATURE_SORT_KEY (UINT64_C(1) << 8) #define EFI_LOADER_FEATURE_SAVED_ENTRY (UINT64_C(1) << 9) #define EFI_LOADER_FEATURE_DEVICETREE (UINT64_C(1) << 10) #define EFI_LOADER_FEATURE_SECUREBOOT_ENROLL (UINT64_C(1) << 11) #define EFI_LOADER_FEATURE_RETAIN_SHIM (UINT64_C(1) << 12) #define EFI_LOADER_FEATURE_MENU_DISABLE (UINT64_C(1) << 13) #define EFI_LOADER_FEATURE_MULTI_PROFILE_UKI (UINT64_C(1) << 14) #define EFI_LOADER_FEATURE_REPORT_URL (UINT64_C(1) << 15) #define EFI_LOADER_FEATURE_TYPE1_UKI (UINT64_C(1) << 16) #define EFI_LOADER_FEATURE_TYPE1_UKI_URL (UINT64_C(1) << 17) /* Features of the stub, i.e. systemd-stub */ #define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION (UINT64_C(1) << 0) #define EFI_STUB_FEATURE_PICK_UP_CREDENTIALS (UINT64_C(1) << 1) #define EFI_STUB_FEATURE_PICK_UP_SYSEXTS (UINT64_C(1) << 2) #define EFI_STUB_FEATURE_THREE_PCRS (UINT64_C(1) << 3) #define EFI_STUB_FEATURE_RANDOM_SEED (UINT64_C(1) << 4) #define EFI_STUB_FEATURE_CMDLINE_ADDONS (UINT64_C(1) << 5) #define EFI_STUB_FEATURE_CMDLINE_SMBIOS (UINT64_C(1) << 6) #define EFI_STUB_FEATURE_DEVICETREE_ADDONS (UINT64_C(1) << 7) #define EFI_STUB_FEATURE_PICK_UP_CONFEXTS (UINT64_C(1) << 8) #define EFI_STUB_FEATURE_MULTI_PROFILE_UKI (UINT64_C(1) << 9) #define EFI_STUB_FEATURE_REPORT_STUB_PARTITION (UINT64_C(1) << 10) #define EFI_STUB_FEATURE_REPORT_URL (UINT64_C(1) << 11) ubustub-1/include/export-vars.h000066400000000000000000000002321504315023600167670ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "proto/loaded-image.h" void export_common_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image); ubustub-1/include/forward.h000066400000000000000000000275231504315023600161550ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /* IWYU pragma: always_keep */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ #include "assert-util.h" /* IWYU pragma: export */ #include "cleanup-util.h" /* IWYU pragma: export */ #include "macro.h" /* IWYU pragma: export */ /* Generic types */ typedef uint64_t usec_t; typedef uint64_t nsec_t; /* Libc/Linux forward declarations */ struct dirent; struct ether_addr; struct fiemap; struct file_handle; struct glob_t; struct group; struct icmp6_hdr; struct in_addr; struct in6_addr; struct inotify_event; struct iovec; struct msghdr; struct passwd; struct pollfd; struct rlimit; struct sgrp; struct shadow; struct signalfd_siginfo; struct siphash; struct sockaddr; struct spwd; struct stat; struct statfs; struct statx_timestamp; struct statx; struct termios; struct tm; struct ucred; /* To forward declare FILE and DIR, we have to declare the internal struct names for them. Since these are * used for C++ symbol name mangling, they're effectively part of the ABI and won't actually change. */ typedef struct _IO_FILE FILE; typedef struct __dirstream DIR; /* 3rd-party library forward declarations */ enum bpf_map_type; struct fdisk_context; struct fdisk_table; struct crypt_device; /* basic/ forward declarations */ typedef void (*hash_func_t)(const void *p, struct siphash *state); typedef int (*compare_func_t)(const void *a, const void *b); typedef compare_func_t comparison_fn_t; typedef int (*comparison_userdata_fn_t)(const void *, const void *, void *); struct hash_ops; struct hw_addr_data; struct in_addr_data; struct iovec_wrapper; union in_addr_union; union sockaddr_union; typedef enum CGroupFlags CGroupFlags; typedef enum CGroupMask CGroupMask; typedef enum ChaseFlags ChaseFlags; typedef enum ExtractFlags ExtractFlags; typedef enum Glyph Glyph; typedef enum ImageClass ImageClass; typedef enum JobMode JobMode; typedef enum RuntimeScope RuntimeScope; typedef enum TimestampStyle TimestampStyle; typedef enum UnitActiveState UnitActiveState; typedef enum UnitDependency UnitDependency; typedef struct Hashmap Hashmap; typedef struct HashmapBase HashmapBase; typedef struct IteratedCache IteratedCache; typedef struct Iterator Iterator; typedef struct OrderedHashmap OrderedHashmap; typedef struct OrderedSet OrderedSet; typedef struct Set Set; typedef struct dual_timestamp dual_timestamp; typedef struct triple_timestamp triple_timestamp; typedef struct LockFile LockFile; typedef struct PidRef PidRef; typedef struct Prioq Prioq; typedef struct RateLimit RateLimit; typedef struct SocketAddress SocketAddress; /* libsystemd/ and libsystemd-network/ forward declarations */ typedef void (*_sd_destroy_t)(void *userdata); typedef union sd_id128 sd_id128_t; typedef struct sd_event sd_event; typedef struct sd_event_source sd_event_source; typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata); typedef _sd_destroy_t sd_event_destroy_t; enum ENUM_TYPE_S64(sd_json_format_flags_t); enum ENUM_TYPE_S64(sd_json_dispatch_flags_t); enum ENUM_TYPE_S64(sd_json_variant_type_t); enum ENUM_TYPE_S64(sd_json_parse_flags_t); typedef enum sd_json_format_flags_t sd_json_format_flags_t; typedef enum sd_json_dispatch_flags_t sd_json_dispatch_flags_t; typedef enum sd_json_variant_type_t sd_json_variant_type_t; typedef enum sd_json_parse_flags_t sd_json_parse_flags_t; typedef struct sd_json_variant sd_json_variant; typedef struct sd_bus sd_bus; typedef struct sd_bus_error sd_bus_error; typedef struct sd_bus_error_map sd_bus_error_map; typedef struct sd_bus_message sd_bus_message; typedef struct sd_bus_slot sd_bus_slot; typedef struct sd_bus_creds sd_bus_creds; typedef struct sd_bus_track sd_bus_track; typedef struct sd_bus_vtable sd_bus_vtable; typedef int (*sd_bus_message_handler_t)(sd_bus_message *m, void *userdata, sd_bus_error *ret_error); typedef int (*sd_bus_property_get_t)(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); typedef int (*sd_bus_property_set_t)(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *ret_error); typedef int (*sd_bus_object_find_t)(sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error); typedef int (*sd_bus_node_enumerator_t)(sd_bus *bus, const char *prefix, void *userdata, char ***ret_nodes, sd_bus_error *ret_error); typedef int (*sd_bus_track_handler_t)(sd_bus_track *track, void *userdata); typedef _sd_destroy_t sd_bus_destroy_t; enum ENUM_TYPE_S64(sd_device_action_t); typedef enum sd_device_action_t sd_device_action_t; typedef struct sd_device sd_device; typedef struct sd_device_enumerator sd_device_enumerator; typedef struct sd_device_monitor sd_device_monitor; typedef struct sd_netlink sd_netlink; typedef struct sd_netlink_message sd_netlink_message; typedef struct sd_netlink_slot sd_netlink_slot; typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata); typedef _sd_destroy_t sd_netlink_destroy_t; typedef struct sd_network_monitor sd_network_monitor; enum ENUM_TYPE_S64(sd_dhcp_lease_server_type_t); enum ENUM_TYPE_S64(sd_lldp_rx_event_t); enum ENUM_TYPE_S64(sd_lldp_multicast_mode_t); enum ENUM_TYPE_S64(sd_ndisc_event_t); typedef enum sd_dhcp_lease_server_type_t sd_dhcp_lease_server_type_t; typedef enum sd_lldp_rx_event_t sd_lldp_rx_event_t; typedef enum sd_lldp_multicast_mode_t sd_lldp_multicast_mode_t; typedef enum sd_ndisc_event_t sd_ndisc_event_t; typedef struct sd_ipv4ll sd_ipv4ll; typedef struct sd_dhcp_client sd_dhcp_client; typedef struct sd_dhcp_lease sd_dhcp_lease; typedef struct sd_dhcp_route sd_dhcp_route; typedef struct sd_dns_resolver sd_dns_resolver; typedef struct sd_dhcp_server sd_dhcp_server; typedef struct sd_ndisc sd_ndisc; typedef struct sd_radv sd_radv; typedef struct sd_dhcp6_client sd_dhcp6_client; typedef struct sd_dhcp6_lease sd_dhcp6_lease; typedef struct sd_lldp_tx sd_lldp_tx; typedef struct sd_lldp_rx sd_lldp_rx; typedef struct sd_lldp_neighbor sd_lldp_neighbor; typedef struct ICMP6Packet ICMP6Packet; enum ENUM_TYPE_S64(sd_varlink_method_flags_t); enum ENUM_TYPE_S64(sd_varlink_interface_flags_t); enum ENUM_TYPE_S64(sd_varlink_symbol_type_t); enum ENUM_TYPE_S64(sd_varlink_field_type_t); enum ENUM_TYPE_S64(sd_varlink_field_direction_t); enum ENUM_TYPE_S64(sd_varlink_field_flags_t); enum ENUM_TYPE_S64(sd_varlink_idl_format_flags_t); enum ENUM_TYPE_S64(sd_varlink_reply_flags_t); enum ENUM_TYPE_S64(sd_varlink_server_flags_t); enum ENUM_TYPE_S64(sd_varlink_invocation_flags_t); typedef enum sd_varlink_method_flags_t sd_varlink_method_flags_t; typedef enum sd_varlink_interface_flags_t sd_varlink_interface_flags_t; typedef enum sd_varlink_symbol_type_t sd_varlink_symbol_type_t; typedef enum sd_varlink_field_type_t sd_varlink_field_type_t; typedef enum sd_varlink_field_direction_t sd_varlink_field_direction_t; typedef enum sd_varlink_field_flags_t sd_varlink_field_flags_t; typedef enum sd_varlink_idl_format_flags_t sd_varlink_idl_format_flags_t; typedef enum sd_varlink_reply_flags_t sd_varlink_reply_flags_t; typedef enum sd_varlink_server_flags_t sd_varlink_server_flags_t; typedef enum sd_varlink_invocation_flags_t sd_varlink_invocation_flags_t; typedef struct sd_varlink sd_varlink; typedef struct sd_varlink_server sd_varlink_server; typedef struct sd_varlink_field sd_varlink_field; typedef struct sd_varlink_symbol sd_varlink_symbol; typedef struct sd_varlink_interface sd_varlink_interface; typedef struct sd_journal sd_journal; typedef struct sd_resolve sd_resolve; typedef struct sd_resolve_query sd_resolve_query; typedef struct sd_hwdb sd_hwdb; /* shared/ forward declarations */ typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata); typedef int (*copy_progress_path_t)(const char *path, const struct stat *st, void *userdata); struct local_address; struct in_addr_prefix; struct in_addr_full; typedef enum AskPasswordFlags AskPasswordFlags; typedef enum BootEntryTokenType BootEntryTokenType; typedef enum BusPrintPropertyFlags BusPrintPropertyFlags; typedef enum BusTransport BusTransport; typedef enum CatFlags CatFlags; typedef enum CertificateSourceType CertificateSourceType; typedef enum DnsCacheMode DnsCacheMode; typedef enum DnsOverTlsMode DnsOverTlsMode; typedef enum DnssecMode DnssecMode; typedef enum Fido2EnrollFlags Fido2EnrollFlags; typedef enum KeySourceType KeySourceType; typedef enum LabelFixFlags LabelFixFlags; typedef enum MountInNamespaceFlags MountInNamespaceFlags; typedef enum NamePolicy NamePolicy; typedef enum OutputFlags OutputFlags; typedef enum OutputMode OutputMode; typedef enum PagerFlags PagerFlags; typedef enum PatternCompileCase PatternCompileCase; typedef enum RemoveFlags RemoveFlags; typedef enum ResolveSupport ResolveSupport; typedef enum TPM2Flags TPM2Flags; typedef enum Tpm2Support Tpm2Support; typedef enum Tpm2UserspaceEventType Tpm2UserspaceEventType; typedef enum UnitFileFlags UnitFileFlags; typedef enum UnitFilePresetMode UnitFilePresetMode; typedef enum UnitFileState UnitFileState; typedef enum UnitType UnitType; typedef enum UserDBFlags UserDBFlags; typedef enum UserRecordLoadFlags UserRecordLoadFlags; typedef enum UserStorage UserStorage; typedef struct Bitmap Bitmap; typedef struct BPFProgram BPFProgram; typedef struct BusObjectImplementation BusObjectImplementation; typedef struct CalendarSpec CalendarSpec; typedef struct Condition Condition; typedef struct ConfigSection ConfigSection; typedef struct ConfigTableItem ConfigTableItem; typedef struct CPUSet CPUSet; typedef struct FDSet FDSet; typedef struct Fido2HmacSalt Fido2HmacSalt; typedef struct FirewallContext FirewallContext; typedef struct GroupRecord GroupRecord; typedef struct Image Image; typedef struct ImagePolicy ImagePolicy; typedef struct InstallInfo InstallInfo; typedef struct LookupPaths LookupPaths; typedef struct LoopDevice LoopDevice; typedef struct MountOptions MountOptions; typedef struct OpenFile OpenFile; typedef struct Pkcs11EncryptedKey Pkcs11EncryptedKey; typedef struct Table Table; typedef struct Tpm2Context Tpm2Context; typedef struct Tpm2Handle Tpm2Handle; typedef struct Tpm2PCRValue Tpm2PCRValue; typedef struct UnitInfo UnitInfo; typedef struct UserRecord UserRecord; typedef struct VeritySettings VeritySettings; /* Constants */ /* We duplicate various commonly used constants here so we can keep most static inline functions without * having to include the full header that provides these constants. */ #define AT_FDCWD -100 #define AT_EMPTY_PATH 0x1000 #define AT_SYMLINK_FOLLOW 0x400 #define AT_SYMLINK_NOFOLLOW 0x100 #define MODE_INVALID ((mode_t) -1) #define UID_INVALID ((uid_t) -1) #define GID_INVALID ((gid_t) -1) #define USEC_INFINITY ((usec_t) UINT64_MAX) #define NSEC_INFINITY ((nsec_t) UINT64_MAX) /* MAX_ERRNO is defined as 4095 in linux/err.h. We use the same value here. */ #define ERRNO_MAX 4095 ubustub-1/include/initrd.h000066400000000000000000000006731504315023600157770ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" EFI_STATUS initrd_register( const void *initrd_address, size_t initrd_length, EFI_HANDLE *ret_initrd_handle); EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle); static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) { (void) initrd_unregister(*initrd_handle); *initrd_handle = NULL; } ubustub-1/include/iovec-util-fundamental.h000066400000000000000000000024421504315023600210560ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "assert-fundamental.h" #include "macro-fundamental.h" /* struct iovec is a POSIX userspace construct. Let's introduce it also in EFI mode, it's just so useful */ struct iovec { void *iov_base; size_t iov_len; }; /* This accepts both const and non-const pointers */ #define IOVEC_MAKE(base, len) \ (struct iovec) { \ .iov_base = (void*) (base), \ .iov_len = (len), \ } static inline void iovec_done(struct iovec *iovec) { /* A _cleanup_() helper that frees the iov_base in the iovec */ assert(iovec); iovec->iov_base = mfree(iovec->iov_base); iovec->iov_len = 0; } static inline bool iovec_is_set(const struct iovec *iovec) { /* Checks if the iovec points to a non-empty chunk of memory */ return iovec && iovec->iov_len > 0 && iovec->iov_base; } static inline bool iovec_is_valid(const struct iovec *iovec) { /* Checks if the iovec is either NULL, empty or points to a valid bit of memory */ return !iovec || (iovec->iov_base || iovec->iov_len == 0); } ubustub-1/include/linux.h000066400000000000000000000010501504315023600156330ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "iovec-util-fundamental.h" EFI_STATUS linux_exec( EFI_HANDLE parent, const char16_t *cmdline, const struct iovec *kernel, const struct iovec *initrd); EFI_STATUS linux_exec_efi_handover( EFI_HANDLE parent, const char16_t *cmdline, const struct iovec *kernel, const struct iovec *initrd, size_t kernel_size_in_memory); ubustub-1/include/logarithm.h000066400000000000000000000036561504315023600165000ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include /* Note: log2(0) == log2(1) == 0 here and below. */ #define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0) #define NONCONST_LOG2ULL(x) ({ \ unsigned long long _x = (x); \ _x > 1 ? (unsigned) __builtin_clzll(_x) ^ 63U : 0; \ }) #define LOG2ULL(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2ULL(x), NONCONST_LOG2ULL(x)) static inline unsigned log2u64(uint64_t x) { #if __SIZEOF_LONG_LONG__ == 8 return LOG2ULL(x); #else # error "Wut?" #endif } static inline unsigned u32ctz(uint32_t n) { #if __SIZEOF_INT__ == 4 return n != 0 ? __builtin_ctz(n) : 32; #else # error "Wut?" #endif } #define popcount(n) \ _Generic((n), \ unsigned char: __builtin_popcount(n), \ unsigned short: __builtin_popcount(n), \ unsigned: __builtin_popcount(n), \ unsigned long: __builtin_popcountl(n), \ unsigned long long: __builtin_popcountll(n)) #define CONST_LOG2U(x) ((x) > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1 : 0) #define NONCONST_LOG2U(x) ({ \ unsigned _x = (x); \ _x > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(_x) - 1 : 0; \ }) #define LOG2U(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2U(x), NONCONST_LOG2U(x)) static inline unsigned log2i(int x) { return LOG2U(x); } static inline unsigned log2u(unsigned x) { return LOG2U(x); } static inline unsigned log2u_round_up(unsigned x) { if (x <= 1) return 0; return log2u(x - 1) + 1; } ubustub-1/include/macro-fundamental.h000066400000000000000000000543061504315023600201050ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include #include #include #include /* Temporarily disable some warnings */ #define DISABLE_WARNING_DEPRECATED_DECLARATIONS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #define DISABLE_WARNING_FORMAT_NONLITERAL \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") #define DISABLE_WARNING_MISSING_PROTOTYPES \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") #define DISABLE_WARNING_NONNULL \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wnonnull\"") #define DISABLE_WARNING_SHADOW \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wshadow\"") #define DISABLE_WARNING_STRINGOP_OVERREAD \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wstringop-overread\"") #define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"") #define DISABLE_WARNING_TYPE_LIMITS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") #define DISABLE_WARNING_ADDRESS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Waddress\"") #define DISABLE_WARNING_STRINGOP_TRUNCATION \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"") #define DISABLE_WARNING_REDUNDANT_DECLS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wredundant-decls\"") #if HAVE_WARNING_ZERO_LENGTH_BOUNDS # define DISABLE_WARNING_ZERO_LENGTH_BOUNDS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wzero-length-bounds\"") #else # define DISABLE_WARNING_ZERO_LENGTH_BOUNDS \ _Pragma("GCC diagnostic push") #endif #if HAVE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT # define DISABLE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"") #else # define DISABLE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT \ _Pragma("GCC diagnostic push") #endif #define REENABLE_WARNING \ _Pragma("GCC diagnostic pop") #define _align_(x) __attribute__((__aligned__(x))) #define _alignas_(x) __attribute__((__aligned__(alignof(x)))) #define _alignptr_ __attribute__((__aligned__(sizeof(void *)))) #define _cleanup_(x) __attribute__((__cleanup__(x))) #define _const_ __attribute__((__const__)) #define _deprecated_ __attribute__((__deprecated__)) #define _destructor_ __attribute__((__destructor__)) #define _hidden_ __attribute__((__visibility__("hidden"))) #define _likely_(x) (__builtin_expect(!!(x), 1)) #define _malloc_ __attribute__((__malloc__)) #define _noinline_ __attribute__((noinline)) #define _noreturn_ _Noreturn #define _packed_ __attribute__((__packed__)) #define _printf_(a, b) __attribute__((__format__(printf, a, b))) #define _public_ __attribute__((__visibility__("default"))) #define _pure_ __attribute__((__pure__)) #define _retain_ __attribute__((__retain__)) #define _returns_nonnull_ __attribute__((__returns_nonnull__)) #define _section_(x) __attribute__((__section__(x))) #define _sentinel_ __attribute__((__sentinel__)) #define _unlikely_(x) (__builtin_expect(!!(x), 0)) #define _unused_ __attribute__((__unused__)) #define _used_ __attribute__((__used__)) #define _warn_unused_result_ __attribute__((__warn_unused_result__)) #define _weak_ __attribute__((__weak__)) #define _weakref_(x) __attribute__((__weakref__(#x))) #ifdef __clang__ # define _alloc_(...) #else # define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__))) #endif #if defined(__clang__) && __clang_major__ < 10 # define _fallthrough_ #else # define _fallthrough_ __attribute__((__fallthrough__)) #endif #if __GNUC__ >= 15 # define _nonnull_if_nonzero_(p, n) __attribute__((nonnull_if_nonzero(p, n))) #else # define _nonnull_if_nonzero_(p, n) #endif #define XSTRINGIFY(x) #x #define STRINGIFY(x) XSTRINGIFY(x) /* C23 changed char8_t from char to unsigned char, hence we cannot pass u8 literals to e.g. fputs() without * casting. Let's introduce our own way to declare UTF-8 literals, which casts u8 literals to const char*. */ #define UTF8(s) ((const char*) (u8"" s)) #ifndef __COVERITY__ # define VOID_0 ((void)0) #else # define VOID_0 ((void*)0) #endif #define ELEMENTSOF(x) \ (__builtin_choose_expr( \ !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ sizeof(x)/sizeof((x)[0]), \ VOID_0)) #define XCONCATENATE(x, y) x ## y #define CONCATENATE(x, y) XCONCATENATE(x, y) #define assert_cc(expr) _Static_assert(expr, #expr) #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ /* Note that this works differently from pthread_once(): this macro does * not synchronize code execution, i.e. code that is run conditionalized * on this macro will run concurrently to all other code conditionalized * the same way, there's no ordering or completion enforced. */ #define ONCE __ONCE(UNIQ_T(_once_, UNIQ)) #define __ONCE(o) \ ({ \ static bool (o) = false; \ __atomic_exchange_n(&(o), true, __ATOMIC_SEQ_CST); \ }) #define U64_KB UINT64_C(1024) #define U64_MB (UINT64_C(1024) * U64_KB) #define U64_GB (UINT64_C(1024) * U64_MB) #undef MAX #define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) #define __MAX(aq, a, bq, b) \ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) #ifdef __clang__ # define ABS(a) __builtin_llabs(a) #else # define ABS(a) __builtin_imaxabs(a) #endif assert_cc(sizeof(long long) == sizeof(intmax_t)); #define IS_UNSIGNED_INTEGER_TYPE(type) \ (__builtin_types_compatible_p(typeof(type), unsigned char) || \ __builtin_types_compatible_p(typeof(type), unsigned short) || \ __builtin_types_compatible_p(typeof(type), unsigned) || \ __builtin_types_compatible_p(typeof(type), unsigned long) || \ __builtin_types_compatible_p(typeof(type), unsigned long long)) #define IS_SIGNED_INTEGER_TYPE(type) \ (__builtin_types_compatible_p(typeof(type), signed char) || \ __builtin_types_compatible_p(typeof(type), signed short) || \ __builtin_types_compatible_p(typeof(type), signed) || \ __builtin_types_compatible_p(typeof(type), signed long) || \ __builtin_types_compatible_p(typeof(type), signed long long)) /* Evaluates to (void) if _A or _B are not constant or of different types (being integers of different sizes * is also OK as long as the signedness matches) */ #define CONST_MAX(_A, _B) \ (__builtin_choose_expr( \ __builtin_constant_p(_A) && \ __builtin_constant_p(_B) && \ (__builtin_types_compatible_p(typeof(_A), typeof(_B)) || \ (IS_UNSIGNED_INTEGER_TYPE(_A) && IS_UNSIGNED_INTEGER_TYPE(_B)) || \ (IS_SIGNED_INTEGER_TYPE(_A) && IS_SIGNED_INTEGER_TYPE(_B))), \ ((_A) > (_B)) ? (_A) : (_B), \ VOID_0)) /* takes two types and returns the size of the larger one */ #define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) #define MAX3(x, y, z) \ ({ \ const typeof(x) _c = MAX(x, y); \ MAX(_c, z); \ }) #define MAX4(x, y, z, a) \ ({ \ const typeof(x) _d = MAX3(x, y, z); \ MAX(_d, a); \ }) #undef MIN #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) #define __MIN(aq, a, bq, b) \ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) /* evaluates to (void) if _A or _B are not constant or of different types */ #define CONST_MIN(_A, _B) \ (__builtin_choose_expr( \ __builtin_constant_p(_A) && \ __builtin_constant_p(_B) && \ __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ ((_A) < (_B)) ? (_A) : (_B), \ VOID_0)) #define MIN3(x, y, z) \ ({ \ const typeof(x) _c = MIN(x, y); \ MIN(_c, z); \ }) /* Returns true if the passed integer is a positive power of two */ #define CONST_ISPOWEROF2(x) \ ((x) > 0 && ((x) & ((x) - 1)) == 0) #define ISPOWEROF2(x) \ __builtin_choose_expr( \ __builtin_constant_p(x), \ CONST_ISPOWEROF2(x), \ ({ \ const typeof(x) _x = (x); \ CONST_ISPOWEROF2(_x); \ })) #define ADD_SAFE(ret, a, b) (!__builtin_add_overflow(a, b, ret)) #define INC_SAFE(a, b) __INC_SAFE(UNIQ, a, b) #define __INC_SAFE(q, a, b) \ ({ \ const typeof(a) UNIQ_T(A, q) = (a); \ ADD_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \ }) #define SUB_SAFE(ret, a, b) (!__builtin_sub_overflow(a, b, ret)) #define DEC_SAFE(a, b) __DEC_SAFE(UNIQ, a, b) #define __DEC_SAFE(q, a, b) \ ({ \ const typeof(a) UNIQ_T(A, q) = (a); \ SUB_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \ }) #define MUL_SAFE(ret, a, b) (!__builtin_mul_overflow(a, b, ret)) #define MUL_ASSIGN_SAFE(a, b) __MUL_ASSIGN_SAFE(UNIQ, a, b) #define __MUL_ASSIGN_SAFE(q, a, b) \ ({ \ const typeof(a) UNIQ_T(A, q) = (a); \ MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \ }) #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) #define __LESS_BY(aq, a, bq, b) \ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \ }) #define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b)) #define __CMP(aq, a, bq, b) \ ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \ }) #undef CLAMP #define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) #define __CLAMP(xq, x, lowq, low, highq, high) \ ({ \ const typeof(x) UNIQ_T(X, xq) = (x); \ const typeof(low) UNIQ_T(LOW, lowq) = (low); \ const typeof(high) UNIQ_T(HIGH, highq) = (high); \ UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \ UNIQ_T(HIGH, highq) : \ UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \ UNIQ_T(LOW, lowq) : \ UNIQ_T(X, xq); \ }) /* [(x + y - 1) / y] suffers from an integer overflow, even though the * computation should be possible in the given type. Therefore, we use * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the * quotient and the remainder, so both should be equally fast. */ #define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y)) #define __DIV_ROUND_UP(xq, x, yq, y) \ ({ \ const typeof(x) UNIQ_T(X, xq) = (x); \ const typeof(y) UNIQ_T(Y, yq) = (y); \ (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \ }) /* Rounds up x to the next multiple of y. Resolves to typeof(x) -1 in case of overflow */ #define __ROUND_UP(q, x, y) \ ({ \ const typeof(y) UNIQ_T(A, q) = (y); \ const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \ typeof(x) UNIQ_T(C, q); \ MUL_SAFE(&UNIQ_T(C, q), UNIQ_T(B, q), UNIQ_T(A, q)) ? UNIQ_T(C, q) : (typeof(x)) -1; \ }) #define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y)) #define CASE_F_1(X) case X: #define CASE_F_2(X, ...) case X: CASE_F_1( __VA_ARGS__) #define CASE_F_3(X, ...) case X: CASE_F_2( __VA_ARGS__) #define CASE_F_4(X, ...) case X: CASE_F_3( __VA_ARGS__) #define CASE_F_5(X, ...) case X: CASE_F_4( __VA_ARGS__) #define CASE_F_6(X, ...) case X: CASE_F_5( __VA_ARGS__) #define CASE_F_7(X, ...) case X: CASE_F_6( __VA_ARGS__) #define CASE_F_8(X, ...) case X: CASE_F_7( __VA_ARGS__) #define CASE_F_9(X, ...) case X: CASE_F_8( __VA_ARGS__) #define CASE_F_10(X, ...) case X: CASE_F_9( __VA_ARGS__) #define CASE_F_11(X, ...) case X: CASE_F_10( __VA_ARGS__) #define CASE_F_12(X, ...) case X: CASE_F_11( __VA_ARGS__) #define CASE_F_13(X, ...) case X: CASE_F_12( __VA_ARGS__) #define CASE_F_14(X, ...) case X: CASE_F_13( __VA_ARGS__) #define CASE_F_15(X, ...) case X: CASE_F_14( __VA_ARGS__) #define CASE_F_16(X, ...) case X: CASE_F_15( __VA_ARGS__) #define CASE_F_17(X, ...) case X: CASE_F_16( __VA_ARGS__) #define CASE_F_18(X, ...) case X: CASE_F_17( __VA_ARGS__) #define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__) #define CASE_F_20(X, ...) case X: CASE_F_19( __VA_ARGS__) #define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME #define FOR_EACH_MAKE_CASE(...) \ GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ (__VA_ARGS__) #define IN_SET(x, first, ...) \ ({ \ bool _found = false; \ /* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \ * here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \ static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ switch (x) { \ FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \ _found = true; \ break; \ default: \ ; \ } \ _found; \ }) /* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ #define TAKE_GENERIC(var, type, nullvalue) \ ({ \ type *_pvar_ = &(var); \ type _var_ = *_pvar_; \ type _nullvalue_ = nullvalue; \ *_pvar_ = _nullvalue_; \ _var_; \ }) #define TAKE_PTR_TYPE(ptr, type) TAKE_GENERIC(ptr, type, NULL) #define TAKE_PTR(ptr) TAKE_PTR_TYPE(ptr, typeof(ptr)) #define TAKE_STRUCT_TYPE(s, type) TAKE_GENERIC(s, type, {}) #define TAKE_STRUCT(s) TAKE_STRUCT_TYPE(s, typeof(s)) /* * STRLEN - return the length of a string literal, minus the trailing NUL byte. * Contrary to strlen(), this is a constant expression. * @x: a string literal. */ #define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0]))) DISABLE_WARNING_REDUNDANT_DECLS; void free(void *p); REENABLE_WARNING; #define mfree(memory) \ ({ \ free(memory); \ (typeof(memory)) NULL; \ }) #define UPDATE_FLAG(orig, flag, b) \ ((b) ? ((orig) | (flag)) : ((orig) & ~(flag))) #define SET_FLAG(v, flag, b) \ (v) = UPDATE_FLAG(v, flag, b) #define FLAGS_SET(v, flags) \ ((~(v) & (flags)) == 0) typedef struct { int _empty[0]; } dummy_t; assert_cc(sizeof(dummy_t) == 0); /* Restriction/bug (see below) was fixed in GCC 15 and clang 19. */ #if __GNUC__ >= 15 || (defined(__clang__) && __clang_major__ >= 19) #define DECLARE_FLEX_ARRAY(type, name) type name[] #else /* Declare a flexible array usable in a union. * This is essentially a work-around for a pointless constraint in C99 * and might go away in some future version of the standard. * * See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3080ea5553cc909b000d1f1d964a9041962f2c5b */ #define DECLARE_FLEX_ARRAY(type, name) \ struct { \ dummy_t __empty__ ## name; \ type name[]; \ } #endif /* Declares an ELF read-only string section that does not occupy memory at runtime. */ #define DECLARE_NOALLOC_SECTION(name, text) \ asm(".pushsection " name ",\"S\"\n\t" \ ".ascii " STRINGIFY(text) "\n\t" \ ".popsection\n") #ifdef SBAT_DISTRO #define DECLARE_SBAT(text) DECLARE_NOALLOC_SECTION(".sbat", text) #else #define DECLARE_SBAT(text) #endif #define typeof_field(struct_type, member) typeof(((struct_type *) 0)->member) #define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member) #define endoffsetof_field(struct_type, member) (offsetof(struct_type, member) + sizeof_field(struct_type, member)) #define voffsetof(v, member) offsetof(typeof(v), member) #define _FOREACH_ARRAY(i, array, num, m, end) \ for (typeof(array[0]) *i = (array), *end = ({ \ typeof(num) m = (num); \ (i && m > 0) ? i + m : NULL; \ }); end && i < end; i++) #define FOREACH_ARRAY(i, array, num) \ _FOREACH_ARRAY(i, array, num, UNIQ_T(m, UNIQ), UNIQ_T(end, UNIQ)) #define FOREACH_ELEMENT(i, array) \ FOREACH_ARRAY(i, array, ELEMENTSOF(array)) #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); #define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) /* In GCC 14 (C23) we can force enums to have the right types, and not solely rely on language extensions anymore */ #if __GNUC__ >= 14 || __STDC_VERSION__ >= 202311L # define ENUM_TYPE_S64(id) id : int64_t #else # define ENUM_TYPE_S64(id) id #endif ubustub-1/include/macro.h000066400000000000000000000230231504315023600156010ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "macro-fundamental.h" /* IWYU pragma: export */ #if !defined(HAS_FEATURE_MEMORY_SANITIZER) # if defined(__has_feature) # if __has_feature(memory_sanitizer) # define HAS_FEATURE_MEMORY_SANITIZER 1 # endif # endif # if !defined(HAS_FEATURE_MEMORY_SANITIZER) # define HAS_FEATURE_MEMORY_SANITIZER 0 # endif #endif #if !defined(HAS_FEATURE_ADDRESS_SANITIZER) # ifdef __SANITIZE_ADDRESS__ # define HAS_FEATURE_ADDRESS_SANITIZER 1 # elif defined(__has_feature) # if __has_feature(address_sanitizer) # define HAS_FEATURE_ADDRESS_SANITIZER 1 # endif # endif # if !defined(HAS_FEATURE_ADDRESS_SANITIZER) # define HAS_FEATURE_ADDRESS_SANITIZER 0 # endif #endif /* Note: on GCC "no_sanitize_address" is a function attribute only, on llvm it may also be applied to global * variables. We define a specific macro which knows this. Note that on GCC we don't need this decorator so much, since * our primary use case for this attribute is registration structures placed in named ELF sections which shall not be * padded, but GCC doesn't pad those anyway if AddressSanitizer is enabled. */ #if HAS_FEATURE_ADDRESS_SANITIZER && defined(__clang__) #define _variable_no_sanitize_address_ __attribute__((__no_sanitize_address__)) #else #define _variable_no_sanitize_address_ #endif /* Apparently there's no has_feature() call defined to check for ubsan, hence let's define this * unconditionally on llvm */ #if defined(__clang__) #define _function_no_sanitize_float_cast_overflow_ __attribute__((no_sanitize("float-cast-overflow"))) #else #define _function_no_sanitize_float_cast_overflow_ #endif /* test harness */ #define EXIT_TEST_SKIP 77 static inline uint64_t u64_multiply_safe(uint64_t a, uint64_t b) { if (_unlikely_(a != 0 && b > (UINT64_MAX / a))) return 0; /* overflow */ return a * b; } /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ static inline unsigned long ALIGN_POWER2(unsigned long u) { /* Avoid subtraction overflow */ if (u == 0) return 0; /* clz(0) is undefined */ if (u == 1) return 1; /* left-shift overflow is undefined */ if (__builtin_clzl(u - 1UL) < 1) return 0; return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); } /* * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. */ #define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member) #define __container_of(uniq, ptr, type, member) \ ({ \ const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \ (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \ }) #define PTR_TO_INT(p) ((int) ((intptr_t) (p))) #define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT(p) ((unsigned) ((uintptr_t) (p))) #define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) #define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) #define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_UINT8(p) ((uint8_t) ((uintptr_t) (p))) #define UINT8_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) #define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) #define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) #define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) #define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) #define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define CHAR_TO_STR(x) ((char[2]) { x, 0 }) #define char_array_0(x) x[sizeof(x)-1] = 0; /* Maximum buffer size needed for formatting an unsigned integer type as hex, including space for '0x' * prefix and trailing NUL suffix. */ #define HEXADECIMAL_STR_MAX(type) (2 + sizeof(type) * 2 + 1) /* Returns the number of chars needed to format variables of the specified type as a decimal string. Adds in * extra space for a negative '-' prefix for signed types. Includes space for the trailing NUL. */ #define DECIMAL_STR_MAX(type) \ ((size_t) IS_SIGNED_INTEGER_TYPE(type) + 1U + \ (sizeof(type) <= 1 ? 3U : \ sizeof(type) <= 2 ? 5U : \ sizeof(type) <= 4 ? 10U : \ sizeof(type) <= 8 ? (IS_SIGNED_INTEGER_TYPE(type) ? 19U : 20U) : sizeof(int[-2*(sizeof(type) > 8)]))) /* Returns the number of chars needed to format the specified integer value. It's hence more specific than * DECIMAL_STR_MAX() which answers the same question for all possible values of the specified type. Does * *not* include space for a trailing NUL. (If you wonder why we special case _x_ == 0 here: it's to trick * out gcc's -Wtype-limits, which would complain on comparing an unsigned type with < 0, otherwise. By * special-casing == 0 here first, we can use <= 0 instead of < 0 to trick out gcc.) */ #define DECIMAL_STR_WIDTH(x) \ ({ \ typeof(x) _x_ = (x); \ size_t ans; \ if (_x_ == 0) \ ans = 1; \ else { \ ans = _x_ <= 0 ? 2 : 1; \ while ((_x_ /= 10) != 0) \ ans++; \ } \ ans; \ }) #define SWAP_TWO(x, y) do { \ typeof(x) _t = (x); \ (x) = (y); \ (y) = (_t); \ } while (false) #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) #define STRV_MAKE_EMPTY ((char*[1]) { NULL }) #define STRV_MAKE_CONST(...) ((const char* const*) ((const char*[]) { __VA_ARGS__, NULL })) /* Pointers range from NULL to POINTER_MAX */ #define POINTER_MAX ((void*) UINTPTR_MAX) /* A macro to force copying of a variable from memory. This is useful whenever we want to read something from * memory and want to make sure the compiler won't optimize away the destination variable for us. It's not * supposed to be a full CPU memory barrier, i.e. CPU is still allowed to reorder the reads, but it is not * allowed to remove our local copies of the variables. We want this to work for unaligned memory, hence * memcpy() is great for our purposes. */ #define READ_NOW(x) \ ({ \ typeof(x) _copy; \ memcpy(&_copy, &(x), sizeof(_copy)); \ asm volatile ("" : : : "memory"); \ _copy; \ }) #define saturate_add(x, y, limit) \ ({ \ typeof(limit) _x = (x); \ typeof(limit) _y = (y); \ _x > (limit) || _y >= (limit) - _x ? (limit) : _x + _y; \ }) static inline size_t size_add(size_t x, size_t y) { return saturate_add(x, y, SIZE_MAX); } /* A little helper for subtracting 1 off a pointer in a safe UB-free way. This is intended to be used for * loops that count down from a high pointer until some base. A naive loop would implement this like this: * * for (p = end-1; p >= base; p--) … * * But this is not safe because p before the base is UB in C. With this macro the loop becomes this instead: * * for (p = PTR_SUB1(end, base); p; p = PTR_SUB1(p, base)) … * * And is free from UB! */ #define PTR_SUB1(p, base) \ ({ \ typeof(p) _q = (p); \ _q && _q > (base) ? &_q[-1] : NULL; \ }) /* Iterate through each argument passed. All must be the same type as 'entry' or must be implicitly * convertible. The iteration variable 'entry' must already be defined. */ #define FOREACH_ARGUMENT(entry, ...) \ _FOREACH_ARGUMENT(entry, UNIQ_T(_entries_, UNIQ), UNIQ_T(_current_, UNIQ), UNIQ_T(_va_sentinel_, UNIQ), ##__VA_ARGS__) #define _FOREACH_ARGUMENT(entry, _entries_, _current_, _va_sentinel_, ...) \ for (typeof(entry) _va_sentinel_[1] = {}, _entries_[] = { __VA_ARGS__ __VA_OPT__(,) _va_sentinel_[0] }, *_current_ = _entries_; \ ((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \ _current_++) ubustub-1/include/measure.h000066400000000000000000000041471504315023600161470ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #if ENABLE_TPM bool tpm_present(void); /* Routines for boot-time TPM PCR measurement as well as submitting an event log entry about it. The latter * can be done with two different event log record types. For old stuff we use EV_IPL (which is legacy, and * not great to recognize properly during PCR validation). For new stuff we use properly tagged * EV_EVENT_TAG record. */ /* Old stuff is logged as EV_IPL */ EFI_STATUS tpm_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured); EFI_STATUS tpm_log_ipl_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char *description, bool *ret_measured); /* New stuff is logged as EV_EVENT_TAG */ EFI_STATUS tpm_log_tagged_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, uint32_t event_id, const char16_t *description, bool *ret_measured); EFI_STATUS tpm_log_load_options(const char16_t *cmdline, bool *ret_measured); #else static inline bool tpm_present(void) { return false; } static inline EFI_STATUS tpm_log_ipl_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) { if (ret_measured) *ret_measured = false; return EFI_SUCCESS; } static inline EFI_STATUS tpm_log_ipl_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char *description, bool *ret_measured) { if (ret_measured) *ret_measured = false; return EFI_SUCCESS; } static inline EFI_STATUS tpm_log_tagged_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, uint32_t event_id, const char16_t *description, bool *ret_measured) { if (ret_measured) *ret_measured = false; return EFI_SUCCESS; } static inline EFI_STATUS tpm_log_load_options(const char16_t *cmdline, bool *ret_measured) { if (ret_measured) *ret_measured = false; return EFI_SUCCESS; } #endif ubustub-1/include/memory-util-fundamental.h000066400000000000000000000122601504315023600212600ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include #include "efi-string.h" #include "assert-fundamental.h" #include "cleanup-fundamental.h" #include "macro-fundamental.h" #define memzero(x, l) \ ({ \ size_t _l_ = (l); \ _l_ > 0 ? memset((x), 0, _l_) : (x); \ }) static inline void *explicit_bzero_safe(void *p, size_t l) { if (p && l > 0) { memset(p, 0, l); __asm__ __volatile__("" : : "r"(p) : "memory"); } return p; } struct VarEraser { /* NB: This is a pointer to memory to erase in case of CLEANUP_ERASE(). Pointer to pointer to memory * to erase in case of CLEANUP_ERASE_PTR() */ void *p; size_t size; }; static inline void erase_var(struct VarEraser *e) { explicit_bzero_safe(e->p, e->size); } /* Mark var to be erased when leaving scope. */ #define CLEANUP_ERASE(var) \ _cleanup_(erase_var) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \ .p = &(var), \ .size = sizeof(var), \ } static inline void erase_varp(struct VarEraser *e) { /* Very similar to erase_var(), but assumes `p` is a pointer to a pointer whose memory shall be destructed. */ if (!e->p) return; explicit_bzero_safe(*(void**) e->p, e->size); } /* Mark pointer so that memory pointed to is erased when leaving scope. Note: this takes a pointer to the * specified pointer, instead of just a copy of it. This is to allow callers to invalidate the pointer after * use, if they like, disabling our automatic erasure (for example because they succeeded with whatever they * wanted to do and now intend to return the allocated buffer to their caller without it being erased). */ #define CLEANUP_ERASE_PTR(ptr, sz) \ _cleanup_(erase_varp) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \ .p = (ptr), \ .size = (sz), \ } static inline size_t ALIGN_TO(size_t l, size_t ali) { assert(ISPOWEROF2(ali)); if (l > SIZE_MAX - (ali - 1)) return SIZE_MAX; /* indicate overflow */ return ((l + (ali - 1)) & ~(ali - 1)); } static inline uint64_t ALIGN_TO_U64(uint64_t l, uint64_t ali) { assert(ISPOWEROF2(ali)); if (l > UINT64_MAX - (ali - 1)) return UINT64_MAX; /* indicate overflow */ return ((l + (ali - 1)) & ~(ali - 1)); } static inline size_t ALIGN_DOWN(size_t l, size_t ali) { assert(ISPOWEROF2(ali)); return l & ~(ali - 1); } static inline uint64_t ALIGN_DOWN_U64(uint64_t l, uint64_t ali) { assert(ISPOWEROF2(ali)); return l & ~(ali - 1); } static inline size_t ALIGN_OFFSET(size_t l, size_t ali) { assert(ISPOWEROF2(ali)); return l & (ali - 1); } static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { assert(ISPOWEROF2(ali)); return l & (ali - 1); } #define ALIGN2(l) ALIGN_TO(l, 2) #define ALIGN4(l) ALIGN_TO(l, 4) #define ALIGN8(l) ALIGN_TO(l, 8) #define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p)) #define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p)) #define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p)) #define ALIGN(l) ALIGN_TO(l, sizeof(void*)) #define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p))) /* Checks if the specified pointer is aligned as appropriate for the specific type */ #define IS_ALIGNED16(p) (((uintptr_t) p) % alignof(uint16_t) == 0) #define IS_ALIGNED32(p) (((uintptr_t) p) % alignof(uint32_t) == 0) #define IS_ALIGNED64(p) (((uintptr_t) p) % alignof(uint64_t) == 0) /* Same as ALIGN_TO but callable in constant contexts. */ #define CONST_ALIGN_TO(l, ali) \ __builtin_choose_expr( \ __builtin_constant_p(l) && \ __builtin_constant_p(ali) && \ CONST_ISPOWEROF2(ali) && \ (l <= SIZE_MAX - (ali - 1)), /* overflow? */ \ ((l) + (ali) - 1) & ~((ali) - 1), \ VOID_0) /* Similar to ((t *) (void *) (p)) to cast a pointer. The macro asserts that the pointer has a suitable * alignment for type "t". This exists for places where otherwise "-Wcast-align=strict" would issue a * warning or if you want to assert that the cast gives a pointer of suitable alignment. */ #define CAST_ALIGN_PTR(t, p) \ ({ \ const void *_p = (p); \ assert(((uintptr_t) _p) % alignof(t) == 0); \ (t *) _p; \ }) ubustub-1/include/memory-util.h000066400000000000000000000070421504315023600167660ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include #include "forward.h" #include "memory-util-fundamental.h" /* IWYU pragma: export */ size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO(l, page_size()) #define PAGE_ALIGN_U64(l) ALIGN_TO_U64(l, page_size()) #define PAGE_ALIGN_DOWN(l) ALIGN_DOWN(l, page_size()) #define PAGE_ALIGN_DOWN_U64(l) ALIGN_DOWN_U64(l, page_size()) #define PAGE_OFFSET(l) ALIGN_OFFSET(l, page_size()) #define PAGE_OFFSET_U64(l) ALIGN_OFFSET_U64(l, page_size()) /* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */ static inline void* memcpy_safe(void *dst, const void *src, size_t n) { if (n == 0) return dst; assert(src); return memcpy(dst, src, n); } /* Normal mempcpy() requires src to be nonnull. We do nothing if n is 0. */ static inline void* mempcpy_safe(void *dst, const void *src, size_t n) { if (n == 0) return dst; assert(src); return mempcpy(dst, src, n); } #define _mempcpy_typesafe(dst, src, n, sz) \ ({ \ size_t sz; \ assert_se(MUL_SAFE(&sz, sizeof((dst)[0]), n)); \ (typeof((dst)[0])*) mempcpy_safe(dst, src, sz); \ }) #define mempcpy_typesafe(dst, src, n) \ _mempcpy_typesafe(dst, src, n, UNIQ_T(sz, UNIQ)) /* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */ static inline int memcmp_safe(const void *s1, const void *s2, size_t n) { if (n == 0) return 0; assert(s1); assert(s2); return memcmp(s1, s2, n); } /* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */ static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) { return memcmp_safe(s1, s2, MIN(n1, n2)) ?: CMP(n1, n2); } #define zero(x) (memzero(&(x), sizeof(x))) bool memeqbyte(uint8_t byte, const void *data, size_t length) _nonnull_if_nonzero_(2, 3); #define memeqzero(data, length) memeqbyte(0x00, data, length) #define eqzero(x) memeqzero(x, sizeof(x)) static inline void* mempset(void *s, int c, size_t n) { memset(s, c, n); return (uint8_t*) s + n; } /* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ static inline void* memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { if (needlelen <= 0) return (void*) haystack; if (haystacklen < needlelen) return NULL; assert(haystack); assert(needle); return memmem(haystack, haystacklen, needle, needlelen); } static inline void* mempmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { const uint8_t *p; p = memmem_safe(haystack, haystacklen, needle, needlelen); if (!p) return NULL; return (uint8_t*) p + needlelen; } void* erase_and_free(void *p); static inline void erase_and_freep(void *p) { erase_and_free(*(void**) p); } /* Use with _cleanup_ to erase a single 'char' when leaving scope */ static inline void erase_char(char *p) { explicit_bzero_safe(p, sizeof(char)); } /* Makes a copy of the buffer with reversed order of bytes */ void* memdup_reverse(const void *mem, size_t size); ubustub-1/include/part-discovery.h000066400000000000000000000007331504315023600174560ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define XBOOTLDR_GUID \ { 0xbc13c2ff, 0x59e6, 0x4262, { 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } } #define ESP_GUID \ { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } } EFI_STATUS partition_open(const EFI_GUID *type, EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir); char16_t *disk_get_part_uuid(EFI_HANDLE *handle); ubustub-1/include/pe.h000066400000000000000000000043101504315023600151020ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" /* This is the actual PE format of the section header */ typedef struct PeSectionHeader { uint8_t Name[8]; uint32_t VirtualSize; uint32_t VirtualAddress; uint32_t SizeOfRawData; uint32_t PointerToRawData; uint32_t PointerToRelocations; uint32_t PointerToLinenumbers; uint16_t NumberOfRelocations; uint16_t NumberOfLinenumbers; uint32_t Characteristics; } _packed_ PeSectionHeader; /* This is a subset of the full PE section header structure, with validated values, and without * the noise. */ typedef struct PeSectionVector { size_t memory_size; /* Size of the section in memory (corresponds to VirtualSize field) */ size_t memory_offset; /* Offset in memory, relative to base address */ uint64_t file_size; /* Amount of bytes of the section read from disk (possibly aligned to FileAlignment in case VirtualSize > SizeOfRawData). */ uint64_t file_offset; /* Offset on disk, relative to beginning of file */ } PeSectionVector; static inline bool PE_SECTION_VECTOR_IS_SET(const PeSectionVector *v) { return v && v->memory_size != 0; } EFI_STATUS pe_section_table_from_base( const void *base, const PeSectionHeader **ret_section_table, size_t *ret_n_section_table); EFI_STATUS pe_section_table_from_file( EFI_FILE *handle, PeSectionHeader **ret_section_table, size_t *ret_n_section_table); void pe_locate_sections( const PeSectionHeader section_table[], size_t n_section_table, const char* const section_names[], size_t validate_base, PeSectionVector sections[]); EFI_STATUS pe_memory_locate_sections( const void *base, const char *const section_names[], PeSectionVector sections[]); EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_entry_point, uint32_t *ret_compat_entry_point, uint64_t *ret_image_base, size_t *ret_size_in_memory); EFI_STATUS pe_kernel_check_no_relocation(const void *base); ubustub-1/include/proto/000077500000000000000000000000001504315023600154725ustar00rootroot00000000000000ubustub-1/include/proto/block-io.h000066400000000000000000000030361504315023600173440ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_BLOCK_IO_PROTOCOL_GUID \ GUID_DEF(0x0964e5b21, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) typedef struct EFI_BLOCK_IO_PROTOCOL EFI_BLOCK_IO_PROTOCOL; struct EFI_BLOCK_IO_PROTOCOL { uint64_t Revision; struct { uint32_t MediaId; bool RemovableMedia; bool MediaPresent; bool LogicalPartition; bool ReadOnly; bool WriteCaching; uint32_t BlockSize; uint32_t IoAlign; EFI_LBA LastBlock; EFI_LBA LowestAlignedLba; uint32_t LogicalBlocksPerPhysicalBlock; uint32_t OptimalTransferLengthGranularity; } *Media; EFI_STATUS (EFIAPI *Reset)( EFI_BLOCK_IO_PROTOCOL *This, bool ExtendedVerification); EFI_STATUS (EFIAPI *ReadBlocks)( EFI_BLOCK_IO_PROTOCOL *This, uint32_t MediaId, EFI_LBA LBA, size_t BufferSize, void *Buffer); EFI_STATUS (EFIAPI *WriteBlocks)( EFI_BLOCK_IO_PROTOCOL *This, uint32_t MediaId, EFI_LBA LBA, size_t BufferSize, void *Buffer); EFI_STATUS (EFIAPI *FlushBlocks)(EFI_BLOCK_IO_PROTOCOL *This); }; ubustub-1/include/proto/console-control.h000066400000000000000000000020351504315023600207630ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ GUID_DEF(0xf42f7782, 0x12e, 0x4c12, 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21) typedef enum { EfiConsoleControlScreenText, EfiConsoleControlScreenGraphics, EfiConsoleControlScreenMaxValue, } EFI_CONSOLE_CONTROL_SCREEN_MODE; typedef struct EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; struct EFI_CONSOLE_CONTROL_PROTOCOL { EFI_STATUS (EFIAPI *GetMode)( EFI_CONSOLE_CONTROL_PROTOCOL *This, EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, bool *UgaExists, bool *StdInLocked); EFI_STATUS (EFIAPI *SetMode)( EFI_CONSOLE_CONTROL_PROTOCOL *This, EFI_CONSOLE_CONTROL_SCREEN_MODE Mode); EFI_STATUS(EFIAPI *LockStdIn)( EFI_CONSOLE_CONTROL_PROTOCOL *This, char16_t *Password); }; ubustub-1/include/proto/device-path.h000066400000000000000000000055621504315023600200440ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_DEVICE_PATH_PROTOCOL_GUID \ GUID_DEF(0x09576e91, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ GUID_DEF(0x8b843e20, 0x8132, 0x4852, 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) #define EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID \ GUID_DEF(0x05c99a21, 0xc70f, 0x4ad2, 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e) /* Device path types. */ enum { HARDWARE_DEVICE_PATH = 0x01, ACPI_DEVICE_PATH = 0x02, MESSAGING_DEVICE_PATH = 0x03, MEDIA_DEVICE_PATH = 0x04, BBS_DEVICE_PATH = 0x05, END_DEVICE_PATH_TYPE = 0x7f, }; /* Device path sub-types. */ enum { END_INSTANCE_DEVICE_PATH_SUBTYPE = 0x01, END_ENTIRE_DEVICE_PATH_SUBTYPE = 0xff, MEDIA_HARDDRIVE_DP = 0x01, MEDIA_VENDOR_DP = 0x03, MEDIA_FILEPATH_DP = 0x04, MEDIA_PIWG_FW_FILE_DP = 0x06, MEDIA_PIWG_FW_VOL_DP = 0x07, MSG_URI_DP = 24, }; struct _packed_ EFI_DEVICE_PATH_PROTOCOL { uint8_t Type; uint8_t SubType; uint16_t Length; }; typedef struct { EFI_DEVICE_PATH Header; EFI_GUID Guid; } _packed_ VENDOR_DEVICE_PATH; #define MBR_TYPE_PCAT 0x01U #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02U #define NO_DISK_SIGNATURE 0x00U #define SIGNATURE_TYPE_MBR 0x01U #define SIGNATURE_TYPE_GUID 0x02U typedef struct { EFI_DEVICE_PATH Header; uint32_t PartitionNumber; uint64_t PartitionStart; uint64_t PartitionSize; union { uint8_t Signature[16]; EFI_GUID SignatureGuid; }; uint8_t MBRType; uint8_t SignatureType; } _packed_ HARDDRIVE_DEVICE_PATH; typedef struct { EFI_DEVICE_PATH Header; char16_t PathName[]; } _packed_ FILEPATH_DEVICE_PATH; typedef struct { EFI_DEVICE_PATH Header; char Uri[]; } _packed_ URI_DEVICE_PATH; typedef struct { char16_t* (EFIAPI *ConvertDeviceNodeToText)( const EFI_DEVICE_PATH *DeviceNode, bool DisplayOnly, bool AllowShortcuts); char16_t* (EFIAPI *ConvertDevicePathToText)( const EFI_DEVICE_PATH *DevicePath, bool DisplayOnly, bool AllowShortcuts); } EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; typedef struct { EFI_DEVICE_PATH* (EFIAPI *ConvertTextToDevicNode)( const char16_t *TextDeviceNode); EFI_DEVICE_PATH* (EFIAPI *ConvertTextToDevicPath)( const char16_t *ConvertTextToDevicPath); } EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL; ubustub-1/include/proto/dt-fixup.h000066400000000000000000000016071504315023600174070ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_DTB_TABLE_GUID \ GUID_DEF(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) #define EFI_DT_FIXUP_PROTOCOL_GUID \ GUID_DEF(0xe617d64c, 0xfe08, 0x46da, 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00) #define EFI_DT_FIXUP_PROTOCOL_REVISION 0x00010000 /* Add nodes and update properties */ #define EFI_DT_APPLY_FIXUPS 0x00000001 /* * Reserve memory according to the /reserved-memory node * and the memory reservation block */ #define EFI_DT_RESERVE_MEMORY 0x00000002 typedef struct EFI_DT_FIXUP_PROTOCOL EFI_DT_FIXUP_PROTOCOL; struct EFI_DT_FIXUP_PROTOCOL { uint64_t Revision; EFI_STATUS (EFIAPI *Fixup)( EFI_DT_FIXUP_PROTOCOL *This, void *Fdt, size_t *BufferSize, uint32_t Flags); }; ubustub-1/include/proto/edid-discovered.h000066400000000000000000000005001504315023600206700ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_EDID_DISCOVERED_PROTOCOL_GUID \ GUID_DEF(0x1c0c34f6, 0xd380, 0x41fa, 0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa) typedef struct { uint32_t SizeOfEdid; uint8_t *Edid; } EFI_EDID_DISCOVERED_PROTOCOL; ubustub-1/include/proto/file-io.h000066400000000000000000000061001504315023600171640ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ GUID_DEF(0x0964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_FILE_INFO_ID \ GUID_DEF(0x009576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_FILE_MODE_READ 0x0000000000000001U #define EFI_FILE_MODE_WRITE 0x0000000000000002U #define EFI_FILE_MODE_CREATE 0x8000000000000000U #define EFI_FILE_READ_ONLY 0x01U #define EFI_FILE_HIDDEN 0x02U #define EFI_FILE_SYSTEM 0x04U #define EFI_FILE_RESERVED 0x08U #define EFI_FILE_DIRECTORY 0x10U #define EFI_FILE_ARCHIVE 0x20U #define EFI_FILE_VALID_ATTR 0x37U typedef struct { uint64_t Size; uint64_t FileSize; uint64_t PhysicalSize; EFI_TIME CreateTime; EFI_TIME LastAccessTime; EFI_TIME ModificationTime; uint64_t Attribute; char16_t FileName[]; } EFI_FILE_INFO; /* Some broken firmware violates the EFI spec by still advancing the readdir * position when returning EFI_BUFFER_TOO_SMALL, effectively skipping over any files when * the buffer was too small. Therefore, we always start with a buffer that should handle FAT32 * max file name length. */ #define EFI_FILE_INFO_MIN_SIZE (offsetof(EFI_FILE_INFO, FileName) + 256U * sizeof(char16_t)) typedef struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL { uint64_t Revision; EFI_STATUS (EFIAPI *OpenVolume)( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, EFI_FILE **Root); }; struct EFI_FILE_PROTOCOL { uint64_t Revision; EFI_STATUS (EFIAPI *Open)( EFI_FILE *This, EFI_FILE **NewHandle, char16_t *FileName, uint64_t OpenMode, uint64_t Attributes); EFI_STATUS (EFIAPI *Close)(EFI_FILE *This); EFI_STATUS (EFIAPI *Delete)(EFI_FILE *This); EFI_STATUS (EFIAPI *Read)( EFI_FILE *This, size_t *BufferSize, void *Buffer); EFI_STATUS (EFIAPI *Write)( EFI_FILE *This, size_t *BufferSize, void *Buffer); EFI_STATUS (EFIAPI *GetPosition)(EFI_FILE *This, uint64_t *Position); EFI_STATUS (EFIAPI *SetPosition)(EFI_FILE *This, uint64_t Position); EFI_STATUS (EFIAPI *GetInfo)( EFI_FILE *This, EFI_GUID *InformationType, size_t *BufferSize, void *Buffer); EFI_STATUS (EFIAPI *SetInfo)( EFI_FILE *This, EFI_GUID *InformationType, size_t BufferSize, void *Buffer); EFI_STATUS (EFIAPI *Flush)(EFI_FILE *This); void *OpenEx; void *ReadEx; void *WriteEx; void *FlushEx; }; ubustub-1/include/proto/graphics-output.h000066400000000000000000000047541504315023600210130ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ GUID_DEF(0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) typedef enum { PixelRedGreenBlueReserved8BitPerColor, PixelBlueGreenRedReserved8BitPerColor, PixelBitMask, PixelBltOnly, PixelFormatMax, } EFI_GRAPHICS_PIXEL_FORMAT; typedef enum { EfiBltVideoFill, EfiBltVideoToBltBuffer, EfiBltBufferToVideo, EfiBltVideoToVideo, EfiGraphicsOutputBltOperationMax, } EFI_GRAPHICS_OUTPUT_BLT_OPERATION; typedef struct { uint32_t RedMask; uint32_t GreenMask; uint32_t BlueMask; uint32_t ReservedMask; } EFI_PIXEL_BITMASK; typedef struct { uint8_t Blue; uint8_t Green; uint8_t Red; uint8_t Reserved; } EFI_GRAPHICS_OUTPUT_BLT_PIXEL; typedef struct { uint32_t Version; uint32_t HorizontalResolution; uint32_t VerticalResolution; EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; EFI_PIXEL_BITMASK PixelInformation; uint32_t PixelsPerScanLine; } EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; typedef struct EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL; struct EFI_GRAPHICS_OUTPUT_PROTOCOL { EFI_STATUS (EFIAPI *QueryMode)( EFI_GRAPHICS_OUTPUT_PROTOCOL *This, uint32_t ModeNumber, size_t *SizeOfInfo, EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info); EFI_STATUS(EFIAPI *SetMode)( EFI_GRAPHICS_OUTPUT_PROTOCOL *This, uint32_t ModeNumber); EFI_STATUS (EFIAPI *Blt)( EFI_GRAPHICS_OUTPUT_PROTOCOL *This, EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, size_t SourceX, size_t SourceY, size_t DestinationX, size_t DestinationY, size_t Width, size_t Height, size_t Delta); struct { uint32_t MaxMode; uint32_t Mode; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; size_t SizeOfInfo; EFI_PHYSICAL_ADDRESS FrameBufferBase; size_t FrameBufferSize; } *Mode; }; ubustub-1/include/proto/load-file.h000066400000000000000000000013771504315023600175070ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_LOAD_FILE_PROTOCOL_GUID \ GUID_DEF(0x56EC3091, 0x954C, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_LOAD_FILE2_PROTOCOL_GUID \ GUID_DEF(0x4006c0c1, 0xfcb3, 0x403e, 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d) typedef struct EFI_LOAD_FILE_PROTOCOL EFI_LOAD_FILE_PROTOCOL; typedef EFI_LOAD_FILE_PROTOCOL EFI_LOAD_FILE2_PROTOCOL; struct EFI_LOAD_FILE_PROTOCOL { EFI_STATUS (EFIAPI *LoadFile)( EFI_LOAD_FILE_PROTOCOL *This, EFI_DEVICE_PATH *FilePath, bool BootPolicy, size_t *BufferSize, void *Buffer); }; ubustub-1/include/proto/loaded-image.h000066400000000000000000000017211504315023600201540ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_LOADED_IMAGE_PROTOCOL_GUID \ GUID_DEF(0x5B1B31A1, 0x9562, 0x11d2, 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B) #define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ GUID_DEF(0xbc62157e, 0x3e33, 0x4fec, 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf) typedef EFI_STATUS (EFIAPI *EFI_IMAGE_ENTRY_POINT)( EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable); typedef struct { uint32_t Revision; EFI_HANDLE ParentHandle; EFI_SYSTEM_TABLE *SystemTable; EFI_HANDLE DeviceHandle; EFI_DEVICE_PATH *FilePath; void *Reserved; uint32_t LoadOptionsSize; void *LoadOptions; void *ImageBase; uint64_t ImageSize; EFI_MEMORY_TYPE ImageCodeType; EFI_MEMORY_TYPE ImageDataType; EFI_STATUS (EFIAPI *Unload)(EFI_HANDLE ImageHandle); } EFI_LOADED_IMAGE_PROTOCOL; ubustub-1/include/proto/rng.h000066400000000000000000000012771504315023600164400ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_RNG_PROTOCOL_GUID \ GUID_DEF(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) typedef struct EFI_RNG_PROTOCOL EFI_RNG_PROTOCOL; struct EFI_RNG_PROTOCOL { EFI_STATUS (EFIAPI *GetInfo)( EFI_RNG_PROTOCOL *This, size_t *RNGAlgorithmListSize, EFI_GUID *RNGAlgorithmList); EFI_STATUS (EFIAPI *GetRNG)( EFI_RNG_PROTOCOL *This, EFI_GUID *RNGAlgorithm, size_t RNGValueLength, uint8_t *RNGValue); }; ubustub-1/include/proto/security-arch.h000066400000000000000000000022631504315023600204300ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_SECURITY_ARCH_PROTOCOL_GUID \ GUID_DEF(0xA46423E3, 0x4617, 0x49f1, 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39) #define EFI_SECURITY2_ARCH_PROTOCOL_GUID \ GUID_DEF(0x94ab2f58, 0x1438, 0x4ef1, 0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68) typedef struct EFI_SECURITY_ARCH_PROTOCOL EFI_SECURITY_ARCH_PROTOCOL; typedef struct EFI_SECURITY2_ARCH_PROTOCOL EFI_SECURITY2_ARCH_PROTOCOL; typedef EFI_STATUS (EFIAPI *EFI_SECURITY_FILE_AUTHENTICATION_STATE)( const EFI_SECURITY_ARCH_PROTOCOL *This, uint32_t AuthenticationStatus, const EFI_DEVICE_PATH *File); typedef EFI_STATUS (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION)( const EFI_SECURITY2_ARCH_PROTOCOL *This, const EFI_DEVICE_PATH *DevicePath, void *FileBuffer, size_t FileSize, bool BootPolicy); struct EFI_SECURITY_ARCH_PROTOCOL { EFI_SECURITY_FILE_AUTHENTICATION_STATE FileAuthenticationState; }; struct EFI_SECURITY2_ARCH_PROTOCOL { EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication; }; ubustub-1/include/proto/shell-parameters.h000066400000000000000000000005751504315023600211220ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_SHELL_PARAMETERS_PROTOCOL_GUID \ GUID_DEF(0x752f3136, 0x4e16, 0x4fdc, 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca) typedef struct { char16_t **Argv; size_t Argc; void *StdIn; void *StdOut; void *StdErr; } EFI_SHELL_PARAMETERS_PROTOCOL; ubustub-1/include/proto/simple-text-io.h000066400000000000000000000154131504315023600205270ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ GUID_DEF(0x387477c1, 0x69c7, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ GUID_DEF(0xdd9e7534, 0x7762, 0x4698, 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa) #define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ GUID_DEF(0x387477c2, 0x69c7, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_SHIFT_STATE_VALID 0x80000000U #define EFI_RIGHT_SHIFT_PRESSED 0x00000001U #define EFI_LEFT_SHIFT_PRESSED 0x00000002U #define EFI_RIGHT_CONTROL_PRESSED 0x00000004U #define EFI_LEFT_CONTROL_PRESSED 0x00000008U #define EFI_RIGHT_ALT_PRESSED 0x00000010U #define EFI_LEFT_ALT_PRESSED 0x00000020U #define EFI_RIGHT_LOGO_PRESSED 0x00000040U #define EFI_LEFT_LOGO_PRESSED 0x00000080U #define EFI_MENU_KEY_PRESSED 0x00000100U #define EFI_SYS_REQ_PRESSED 0x00000200U #define EFI_TOGGLE_STATE_VALID 0x80U #define EFI_KEY_STATE_EXPOSED 0x40U #define EFI_SCROLL_LOCK_ACTIVE 0x01U #define EFI_NUM_LOCK_ACTIVE 0x02U #define EFI_CAPS_LOCK_ACTIVE 0x04U enum { EFI_BLACK = 0x00, EFI_BLUE = 0x01, EFI_GREEN = 0x02, EFI_CYAN = EFI_BLUE | EFI_GREEN, EFI_RED = 0x04, EFI_MAGENTA = EFI_BLUE | EFI_RED, EFI_BROWN = EFI_GREEN | EFI_RED, EFI_LIGHTGRAY = EFI_BLUE | EFI_GREEN | EFI_RED, EFI_BRIGHT = 0x08, EFI_DARKGRAY = EFI_BLACK | EFI_BRIGHT, EFI_LIGHTBLUE = EFI_BLUE | EFI_BRIGHT, EFI_LIGHTGREEN = EFI_GREEN | EFI_BRIGHT, EFI_LIGHTCYAN = EFI_CYAN | EFI_BRIGHT, EFI_LIGHTRED = EFI_RED | EFI_BRIGHT, EFI_LIGHTMAGENTA = EFI_MAGENTA | EFI_BRIGHT, EFI_YELLOW = EFI_BROWN | EFI_BRIGHT, EFI_WHITE = EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT, }; #define EFI_TEXT_ATTR(fg, bg) ((fg) | ((bg) << 4)) #define EFI_TEXT_ATTR_SWAP(c) EFI_TEXT_ATTR(((c) & 0xF0U) >> 4, (c) & 0xFU) enum { SCAN_NULL = 0x000, SCAN_UP = 0x001, SCAN_DOWN = 0x002, SCAN_RIGHT = 0x003, SCAN_LEFT = 0x004, SCAN_HOME = 0x005, SCAN_END = 0x006, SCAN_INSERT = 0x007, SCAN_DELETE = 0x008, SCAN_PAGE_UP = 0x009, SCAN_PAGE_DOWN = 0x00A, SCAN_F1 = 0x00B, SCAN_F2 = 0x00C, SCAN_F3 = 0x00D, SCAN_F4 = 0x00E, SCAN_F5 = 0x00F, SCAN_F6 = 0x010, SCAN_F7 = 0x011, SCAN_F8 = 0x012, SCAN_F9 = 0x013, SCAN_F10 = 0x014, SCAN_F11 = 0x015, SCAN_F12 = 0x016, SCAN_ESC = 0x017, SCAN_PAUSE = 0x048, SCAN_F13 = 0x068, SCAN_F14 = 0x069, SCAN_F15 = 0x06A, SCAN_F16 = 0x06B, SCAN_F17 = 0x06C, SCAN_F18 = 0x06D, SCAN_F19 = 0x06E, SCAN_F20 = 0x06F, SCAN_F21 = 0x070, SCAN_F22 = 0x071, SCAN_F23 = 0x072, SCAN_F24 = 0x073, SCAN_MUTE = 0x07F, SCAN_VOLUME_UP = 0x080, SCAN_VOLUME_DOWN = 0x081, SCAN_BRIGHTNESS_UP = 0x100, SCAN_BRIGHTNESS_DOWN = 0x101, SCAN_SUSPEND = 0x102, SCAN_HIBERNATE = 0x103, SCAN_TOGGLE_DISPLAY = 0x104, SCAN_RECOVERY = 0x105, SCAN_EJECT = 0x106, }; typedef struct { uint16_t ScanCode; char16_t UnicodeChar; } EFI_INPUT_KEY; typedef struct { uint32_t KeyShiftState; uint8_t KeyToggleState; } EFI_KEY_STATE; typedef struct { EFI_INPUT_KEY Key; EFI_KEY_STATE KeyState; } EFI_KEY_DATA; struct EFI_SIMPLE_TEXT_INPUT_PROTOCOL { EFI_STATUS (EFIAPI *Reset)( EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, bool ExtendedVerification); EFI_STATUS (EFIAPI *ReadKeyStroke)( EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, EFI_INPUT_KEY *Key); EFI_EVENT WaitForKey; }; typedef struct EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; struct EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { EFI_STATUS (EFIAPI *Reset)( EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, bool ExtendedVerification); EFI_STATUS (EFIAPI *ReadKeyStrokeEx)( EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, EFI_KEY_DATA *KeyData); EFI_EVENT WaitForKeyEx; void *SetState; void *RegisterKeyNotify; void *UnregisterKeyNotify; }; typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL { EFI_STATUS (EFIAPI *Reset)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, bool ExtendedVerification); EFI_STATUS (EFIAPI *OutputString)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, char16_t *String); EFI_STATUS (EFIAPI *TestString)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, char16_t *String); EFI_STATUS (EFIAPI *QueryMode)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, size_t ModeNumber, size_t *Columns, size_t *Rows); EFI_STATUS (EFIAPI *SetMode)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, size_t ModeNumber); EFI_STATUS (EFIAPI *SetAttribute)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, size_t Attribute); EFI_STATUS (EFIAPI *ClearScreen)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This); EFI_STATUS (EFIAPI *SetCursorPosition)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, size_t Column, size_t Row); EFI_STATUS (EFIAPI *EnableCursor)( EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, bool Visible); struct { int32_t MaxMode; int32_t Mode; int32_t Attribute; int32_t CursorColumn; int32_t CursorRow; bool CursorVisible; } *Mode; }; ubustub-1/include/random-seed.h000066400000000000000000000002051504315023600166730ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" EFI_STATUS process_random_seed(EFI_FILE *root_dir); ubustub-1/include/sbat.h000066400000000000000000000016041504315023600154320ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifdef SBAT_DISTRO # include "version.h" # define SBAT_MAGIC "sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md\n" # define SBAT_BOOT_SECTION_TEXT \ SBAT_MAGIC \ SBAT_PROJECT "-boot" ",1,The systemd Developers," SBAT_PROJECT "," PROJECT_VERSION "," PROJECT_URL "\n" \ SBAT_PROJECT "-boot" "." SBAT_DISTRO "," STRINGIFY(SBAT_DISTRO_GENERATION) "," SBAT_DISTRO_SUMMARY "," SBAT_DISTRO_PKGNAME "," SBAT_DISTRO_VERSION "," SBAT_DISTRO_URL "\n" # define SBAT_STUB_SECTION_TEXT \ SBAT_MAGIC \ SBAT_PROJECT "-stub" ",1,The systemd Developers," SBAT_PROJECT "," PROJECT_VERSION "," PROJECT_URL "\n" \ SBAT_PROJECT "-stub" "." SBAT_DISTRO "," STRINGIFY(SBAT_DISTRO_GENERATION) "," SBAT_DISTRO_SUMMARY "," SBAT_DISTRO_PKGNAME "," SBAT_DISTRO_VERSION "," SBAT_DISTRO_URL "\n" #endif ubustub-1/include/secure-boot.h000066400000000000000000000030261504315023600167300ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "efivars-fundamental.h" typedef enum { ENROLL_OFF, /* no Secure Boot key enrollment whatsoever, even manual entries are not generated */ ENROLL_MANUAL, /* Secure Boot key enrollment is strictly manual: manual entries are generated and need to be selected by the user */ ENROLL_IF_SAFE, /* Automatically enroll if it is safe (if we are running inside a VM, for example). */ ENROLL_FORCE, /* Secure Boot key enrollment may be automatic if it is available but might not be safe */ _SECURE_BOOT_ENROLL_MAX, } secure_boot_enroll; typedef enum { ENROLL_ACTION_REBOOT, /* Reboot the system after enrollment */ ENROLL_ACTION_SHUTDOWN, /* Shutdown the system after enrollment */ _SECURE_BOOT_ENROLL_ACTION_MAX, } secure_boot_enroll_action; bool secure_boot_enabled(void); EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force, secure_boot_enroll_action action); typedef bool (*security_validator_t)( const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size); void install_security_override(security_validator_t validator, const void *validator_ctx); void uninstall_security_override(void); const char* secure_boot_enroll_to_string(secure_boot_enroll e) _const_; const char* secure_boot_enroll_action_to_string(secure_boot_enroll_action e) _const_; ubustub-1/include/sha1.h000066400000000000000000000023661504315023600153430ustar00rootroot00000000000000/* SPDX-License-Identifier: LicenseRef-alg-sha1-public-domain */ /* * This is an implementation of the National Institute of Standards * and Technology US Secure Hash Algorithm 1 (SHA1). * * Public api for steve reid's public domain SHA-1 implementation. * This file is in the public domain. */ #pragma once #include #include #define SHA1_DIGEST_SIZE 20 /* Structure to save state of computation between the single steps. */ struct sha1_ctx { uint32_t state[5]; uint32_t count[2]; uint8_t buffer[64]; }; /* Initialize structure containing state of computation. (RFC 3174, 6.1) */ void sha1_init_ctx(struct sha1_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function) update the context for the next LEN bytes starting at BUFFER. LEN does not need to be a multiple of 64. */ void sha1_process_bytes(const void *buffer, size_t size, struct sha1_ctx *ctx); /* Process the remaining bytes in the buffer and write the finalized hash to RESBUF, which should point to 20 bytes of storage. All data written to CTX is erased before returning from the function. */ void *sha1_finish_ctx(struct sha1_ctx *ctx, uint8_t result[static SHA1_DIGEST_SIZE]); ubustub-1/include/sha256.h000066400000000000000000000023561504315023600155160ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include #include #define SHA256_DIGEST_SIZE 32 struct sha256_ctx { uint32_t H[8]; union { uint64_t total64; #define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) #define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) uint32_t total[2]; }; uint32_t buflen; union { uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */ uint32_t buffer32[32]; uint64_t buffer64[16]; }; }; void sha256_init_ctx(struct sha256_ctx *ctx); uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]); void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx); static inline void sha256_process_bytes_and_size(const void *buffer, size_t len, struct sha256_ctx *ctx) { sha256_process_bytes(&len, sizeof(len), ctx); sha256_process_bytes(buffer, len, ctx); } uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]); #define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {}) ubustub-1/include/shim.h000066400000000000000000000007751504315023600154510ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Port to systemd-boot * Copyright © 2017 Max Resch * * Security Policy Handling * Copyright © 2012 * https://github.com/mjg59/efitools */ #pragma once #include "efi.h" bool shim_loaded(void); bool shim_loader_available(void); EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, bool boot_policy, EFI_HANDLE *ret_image); void shim_retain_protocol(void); ubustub-1/include/smbios.h000066400000000000000000000010641504315023600157750ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" bool smbios_in_hypervisor(void); const char* smbios_find_oem_string(const char *name, const char *after); typedef struct RawSmbiosInfo { const char *manufacturer; const char *product_name; const char *product_sku; const char *family; const char *baseboard_product; const char *baseboard_manufacturer; } RawSmbiosInfo; void smbios_raw_info_populate(RawSmbiosInfo *ret_info); void smbios_raw_info_get_cached(RawSmbiosInfo *ret_info); ubustub-1/include/string-util-fundamental.h000066400000000000000000000073541504315023600212660ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "efi-string.h" #include "assert-fundamental.h" #include "macro-fundamental.h" /* What is interpreted as whitespace? */ #define WHITESPACE " \t\n\r" #define NEWLINE "\n\r" #define QUOTES "\"\'" #define COMMENTS "#;" #define GLOB_CHARS "*?[" #define DIGITS "0123456789" #define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS #define ALPHANUMERICAL LETTERS DIGITS #define HEXDIGITS DIGITS "abcdefABCDEF" #define LOWERCASE_HEXDIGITS DIGITS "abcdef" #define URI_RESERVED ":/?#[]@!$&'()*+;=" /* [RFC3986] */ #define URI_UNRESERVED ALPHANUMERICAL "-._~" /* [RFC3986] */ #define URI_VALID URI_RESERVED URI_UNRESERVED /* [RFC3986] */ #define strlen strlen16 #define strcmp strcmp16 #define strncmp strncmp16 #define strcasecmp strcasecmp16 #define strncasecmp strncasecmp16 #define strspn strspn16 #define strcspn strcspn16 #define STR_C(str) (L ## str) typedef char16_t sd_char; #define streq(a,b) (strcmp((a),(b)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) #define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) static inline int strcmp_ptr(const sd_char *a, const sd_char *b) { if (a && b) return strcmp(a, b); return CMP(a, b); } static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) { if (a && b) return strcasecmp(a, b); return CMP(a, b); } static inline bool streq_ptr(const sd_char *a, const sd_char *b) { return strcmp_ptr(a, b) == 0; } static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { return strcasecmp_ptr(a, b) == 0; } static inline size_t strlen_ptr(const sd_char *s) { if (!s) return 0; return strlen(s); } sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_; sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_; sd_char *endswith(const sd_char *s, const sd_char *suffix) _pure_; sd_char *endswith_no_case(const sd_char *s, const sd_char *suffix) _pure_; static inline bool isempty(const sd_char *a) { return !a || a[0] == '\0'; } static inline const sd_char *strempty(const sd_char *s) { return s ?: STR_C(""); } static inline const sd_char *yes_no(bool b) { return b ? STR_C("yes") : STR_C("no"); } static inline const sd_char *on_off(bool b) { return b ? STR_C("on") : STR_C("off"); } static inline const sd_char* comparison_operator(int result) { return result < 0 ? STR_C("<") : result > 0 ? STR_C(">") : STR_C("=="); } int strverscmp_improved(const sd_char *a, const sd_char *b); /* Like startswith(), but operates on arbitrary memory blocks */ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) { assert(token); size_t n = strlen(token) * sizeof(sd_char); if (sz < n) return NULL; assert(p); if (memcmp(p, token, n) != 0) return NULL; return (uint8_t*) p + n; } static inline bool ascii_isdigit(sd_char a) { /* A pure ASCII, locale independent version of isdigit() */ return a >= '0' && a <= '9'; } static inline bool ascii_ishex(sd_char a) { return ascii_isdigit(a) || (a >= 'a' && a <= 'f') || (a >= 'A' && a <= 'F'); } static inline bool ascii_isalpha(sd_char a) { /* A pure ASCII, locale independent version of isalpha() */ return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); } ubustub-1/include/tpm2-pcr.h000066400000000000000000000055171504315023600161540ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once /* The various TPM PCRs we measure into from sd-stub and sd-boot. */ enum { /* The following names for PCRs 0…7 are based on the names in the "TCG PC Client Specific Platform * Firmware Profile Specification" * (https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/) */ TPM2_PCR_PLATFORM_CODE = 0, TPM2_PCR_PLATFORM_CONFIG = 1, TPM2_PCR_EXTERNAL_CODE = 2, TPM2_PCR_EXTERNAL_CONFIG = 3, TPM2_PCR_BOOT_LOADER_CODE = 4, TPM2_PCR_BOOT_LOADER_CONFIG = 5, TPM2_PCR_HOST_PLATFORM = 6, TPM2_PCR_SECURE_BOOT_POLICY = 7, /* The following names for PCRs 9…15 are based on the "Linux TPM PCR Registry" (https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/) */ TPM2_PCR_KERNEL_INITRD = 9, TPM2_PCR_IMA = 10, /* systemd: This TPM PCR is where we extend the sd-stub "payloads" into, before using them. i.e. the kernel * ELF image, embedded initrd, and so on. In contrast to PCR 4 (which also contains this data, given * the whole surrounding PE image is measured into it) this should be reasonably pre-calculatable, * because it *only* consists of static data from the kernel PE image. */ TPM2_PCR_KERNEL_BOOT = 11, /* systemd: This TPM PCR is where sd-stub extends the kernel command line and any passed credentials into. */ TPM2_PCR_KERNEL_CONFIG = 12, /* systemd: This TPM PCR is where we extend the initrd sysext images into which we pass to the booted kernel */ TPM2_PCR_SYSEXTS = 13, TPM2_PCR_SHIM_POLICY = 14, /* systemd: This TPM PCR is where we measure the root fs volume key (and maybe /var/'s) if it is split off */ TPM2_PCR_SYSTEM_IDENTITY = 15, /* As per "TCG PC Client Specific Platform Firmware Profile Specification" again, see above */ TPM2_PCR_DEBUG = 16, TPM2_PCR_APPLICATION_SUPPORT = 23, }; /* The tag used for EV_EVENT_TAG event log records covering the boot loader config */ #define LOADER_CONF_EVENT_TAG_ID UINT32_C(0xf5bc582a) /* The tag used for EV_EVENT_TAG event log records covering DeviceTree blobs */ #define DEVICETREE_ADDON_EVENT_TAG_ID UINT32_C(0x6c46f751) /* The tag used for EV_EVENT_TAG event log records covering initrd addons */ #define INITRD_ADDON_EVENT_TAG_ID UINT32_C(0x49dffe0f) /* The tag used for EV_EVENT_TAG event log records covering ucode addons (effectively initrds) */ #define UCODE_ADDON_EVENT_TAG_ID UINT32_C(0xdac08e1a) /* The tag used for EV_EVENT_TAG event log records covering the selected UKI profile */ #define UKI_PROFILE_EVENT_TAG_ID UINT32_C(0x13aed6db) ubustub-1/include/uki.h000066400000000000000000000041271504315023600152740ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include /* List of PE sections that have special meaning for us in unified kernels. This is the canonical order in * which we measure the sections into TPM PCR 11. PLEASE DO NOT REORDER! */ typedef enum UnifiedSection { UNIFIED_SECTION_LINUX, UNIFIED_SECTION_OSREL, UNIFIED_SECTION_CMDLINE, UNIFIED_SECTION_INITRD, UNIFIED_SECTION_UCODE, UNIFIED_SECTION_SPLASH, UNIFIED_SECTION_DTB, UNIFIED_SECTION_UNAME, UNIFIED_SECTION_SBAT, UNIFIED_SECTION_PCRSIG, UNIFIED_SECTION_PCRPKEY, UNIFIED_SECTION_PROFILE, UNIFIED_SECTION_DTBAUTO, UNIFIED_SECTION_HWIDS, UNIFIED_SECTION_EFIFW, _UNIFIED_SECTION_MAX, } UnifiedSection; extern const char* const unified_sections[_UNIFIED_SECTION_MAX + 1]; static inline bool unified_section_measure(UnifiedSection section) { /* Don't include the PCR signature in the PCR measurements, since they sign the expected result of * the measurement, and hence shouldn't be input to it. */ return section >= 0 && section < _UNIFIED_SECTION_MAX && section != UNIFIED_SECTION_PCRSIG; } /* Max number of profiles per UKI */ #define UNIFIED_PROFILES_MAX 256U /* The native PE machine type, if known, for a full list see: * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types */ #ifndef _IMAGE_FILE_MACHINE_NATIVE # if defined(__x86_64__) # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x8664) # elif defined(__i386__) # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x014c) # elif defined(__ia64__) # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x0200) # elif defined(__aarch64__) # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0xaa64) # elif defined(__arm__) # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x01c0) # elif defined(__riscv) # if __SIZEOF_POINTER__ == 4 # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x5032) # elif __SIZEOF_POINTER__ == 8 # define _IMAGE_FILE_MACHINE_NATIVE UINT16_C(0x5064) # endif # endif #endif ubustub-1/include/unaligned-fundamental.h000066400000000000000000000021331504315023600207410ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include static inline uint16_t unaligned_read_ne16(const void *_u) { const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; return u->x; } static inline uint32_t unaligned_read_ne32(const void *_u) { const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; return u->x; } static inline uint64_t unaligned_read_ne64(const void *_u) { const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; return u->x; } static inline void unaligned_write_ne16(void *_u, uint16_t a) { struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; u->x = a; } static inline void unaligned_write_ne32(void *_u, uint32_t a) { struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; u->x = a; } static inline void unaligned_write_ne64(void *_u, uint64_t a) { struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; u->x = a; } ubustub-1/include/url-discovery.h000066400000000000000000000001751504315023600173120ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" char16_t *disk_get_url(EFI_HANDLE *handle); ubustub-1/include/util.h000066400000000000000000000224421504315023600154610ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "efi.h" #include "memory-util-fundamental.h" #include "proto/file-io.h" /* This is provided by the linker. */ extern uint8_t __executable_start[]; DISABLE_WARNING_REDUNDANT_DECLS; void free(void *p); REENABLE_WARNING; static inline void freep(void *p) { free(*(void **) p); } #define _cleanup_free_ _cleanup_(freep) _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_ void *xmalloc(size_t size); _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_ static inline void *xcalloc(size_t size) { void *t = xmalloc(size); memzero(t, size); return t; } _malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_ static inline void *xcalloc_multiply(size_t n, size_t size) { assert_se(MUL_ASSIGN_SAFE(&size, n)); return xcalloc(size); } _malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_ static inline void *xmalloc_multiply(size_t n, size_t size) { assert_se(MUL_ASSIGN_SAFE(&size, n)); return xmalloc(size); } /* Use malloc attribute as this never returns p like userspace realloc. */ _malloc_ _alloc_(3) _returns_nonnull_ _warn_unused_result_ static inline void *xrealloc(void *p, size_t old_size, size_t new_size) { void *t = xmalloc(new_size); new_size = MIN(old_size, new_size); if (new_size > 0) memcpy(t, p, new_size); free(p); return t; } _malloc_ _alloc_(2) _returns_nonnull_ _warn_unused_result_ static inline void* xmemdup(const void *p, size_t l) { return memcpy(xmalloc(l), p, l); } #define xnew(type, n) ((type *) xmalloc_multiply((n), sizeof(type))) #define xnew0(type, n) ((type *) xcalloc_multiply((n), sizeof(type))) bool free_and_xstrdup16(char16_t **p, const char16_t *s); typedef struct { EFI_PHYSICAL_ADDRESS addr; size_t n_pages; } Pages; static inline void cleanup_pages(Pages *p) { if (p->n_pages == 0) return; #ifdef EFI_DEBUG assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS); #else (void) BS->FreePages(p->addr, p->n_pages); #endif } #define _cleanup_pages_ _cleanup_(cleanup_pages) static inline Pages xmalloc_pages( EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) { assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS); return (Pages) { .addr = addr, .n_pages = n_pages, }; } static inline Pages xmalloc_initrd_pages(size_t n_pages) { /* The original native x86 boot protocol of the Linux kernel was not 64bit safe, hence we try to * allocate memory for the initrds below the 4G boundary on x86, since we don't know early enough * which protocol we'll use to ultimately boot the kernel. This restriction is somewhat obsolete, * since these days we generally prefer the kernel's newer EFI entrypoint instead, which has no such * limitations. There's a good chance that for large allocations we won't be successful, hence * immediately fallback to an unrestricted allocation. On other architectures we do not bother with * any restriction on this, in particular as some of them don't even have RAM mapped to such low * addresses. */ #if defined(__i386__) || defined(__x86_64__) EFI_PHYSICAL_ADDRESS addr = UINT32_MAX; /* Below 4G boundary. */ if (BS->AllocatePages( AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(n_pages), &addr) == EFI_SUCCESS) return (Pages) { .addr = addr, .n_pages = EFI_SIZE_TO_PAGES(n_pages), }; #endif return xmalloc_pages( AllocateAnyPages, EfiLoaderData, EFI_SIZE_TO_PAGES(n_pages), 0 /* Ignored. */); } void convert_efi_path(char16_t *path); char16_t *xstr8_to_path(const char *stra); char16_t *mangle_stub_cmdline(char16_t *cmdline); EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf); EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, uint64_t offset, size_t size, char **content, size_t *content_size); EFI_STATUS file_handle_read(EFI_FILE *handle, uint64_t offset, size_t size, char **ret, size_t *ret_size); static inline void file_closep(EFI_FILE **handle) { if (!*handle) return; (*handle)->Close(*handle); } #define _cleanup_file_close_ _cleanup_(file_closep) static inline void unload_imagep(EFI_HANDLE *image) { if (*image) (void) BS->UnloadImage(*image); } /* Note that GUID is evaluated multiple times! */ #define GUID_FORMAT_STR "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" #define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \ (g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7] void print_at(size_t x, size_t y, size_t attr, const char16_t *str); void clear_screen(size_t attr); typedef int (*compare_pointer_func_t)(const void *a, const void *b); void sort_pointer_array(void **array, size_t n_members, compare_pointer_func_t compare); EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size); EFI_STATUS readdir(EFI_FILE *handle, EFI_FILE_INFO **buffer, size_t *buffer_size); bool is_ascii(const char16_t *f); char16_t **strv_free(char16_t **l); DEFINE_TRIVIAL_CLEANUP_FUNC(char16_t**, strv_free); #define _cleanup_strv_free_ _cleanup_(strv_freep) EFI_STATUS open_directory(EFI_FILE *root_dir, const char16_t *path, EFI_FILE **ret); /* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64-bit, even on * 32-bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the * conversion indirectly: first into uintptr_t and then extended to EFI_PHYSICAL_ADDRESS. */ static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) { return (EFI_PHYSICAL_ADDRESS) (uintptr_t) p; } static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) { /* On 32-bit systems the address might not be convertible (as pointers are 32-bit but * EFI_PHYSICAL_ADDRESS 64-bit) */ assert(addr <= UINTPTR_MAX); return (void *) (uintptr_t) addr; } /* If EFI_DEBUG, print our name and version and also report the address of the image base so a debugger can * be attached. See debug-sd-boot.sh for how this can be done. */ void notify_debugger(const char *identity, bool wait); /* On x86 the compiler assumes a different incoming stack alignment than what we get. * This will cause long long variables to be misaligned when building with * '-mlong-double' (for correct struct layouts). Normally, the compiler realigns the * stack itself on entry, but we have to do this ourselves here as the compiler does * not know that this is our entry point. */ #ifdef __i386__ # define _realign_stack_ __attribute__((force_align_arg_pointer)) #else # define _realign_stack_ #endif #define DEFINE_EFI_MAIN_FUNCTION(func, identity, wait_for_debugger) \ EFI_SYSTEM_TABLE *ST; \ EFI_BOOT_SERVICES *BS; \ EFI_RUNTIME_SERVICES *RT; \ _realign_stack_ \ EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table); \ EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { \ ST = system_table; \ BS = system_table->BootServices; \ RT = system_table->RuntimeServices; \ __stack_chk_guard_init(); \ notify_debugger((identity), (wait_for_debugger)); \ EFI_STATUS err = func(image); \ log_wait(); \ return err; \ } #if defined(__i386__) || defined(__x86_64__) void beep(unsigned beep_count); #else static inline void beep(unsigned beep_count) {} #endif EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file); static inline bool efi_guid_equal(const EFI_GUID *a, const EFI_GUID *b) { return memcmp(a, b, sizeof(EFI_GUID)) == 0; } void *find_configuration_table(const EFI_GUID *guid); char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path); #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define be16toh(x) __builtin_bswap16(x) # define be32toh(x) __builtin_bswap32(x) # define le16toh(x) (x) # define le32toh(x) (x) #else # error "Unexpected byte order in EFI mode?" #endif #define bswap_16(x) __builtin_bswap16(x) #define bswap_32(x) __builtin_bswap32(x) char16_t *url_replace_last_component(const char16_t *url, const char16_t *filename); ubustub-1/include/version.h000066400000000000000000000000141504315023600161600ustar00rootroot00000000000000#define LOL ubustub-1/initrd.c000066400000000000000000000110341504315023600143400ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "initrd.h" #include "proto/device-path.h" #include "proto/load-file.h" #include "util.h" #define LINUX_INITRD_MEDIA_GUID \ GUID_DEF(0x5568e427, 0x68fc, 0x4f3d, 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68) /* extend LoadFileProtocol */ struct initrd_loader { EFI_LOAD_FILE_PROTOCOL load_file; const void *address; size_t length; }; /* static structure for LINUX_INITRD_MEDIA device path see https://github.com/torvalds/linux/blob/v5.13/drivers/firmware/efi/libstub/efi-stub-helper.c */ static const struct { VENDOR_DEVICE_PATH vendor; EFI_DEVICE_PATH end; } _packed_ efi_initrd_device_path = { .vendor = { .Header = { .Type = MEDIA_DEVICE_PATH, .SubType = MEDIA_VENDOR_DP, .Length = sizeof(efi_initrd_device_path.vendor), }, .Guid = LINUX_INITRD_MEDIA_GUID }, .end = { .Type = END_DEVICE_PATH_TYPE, .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, .Length = sizeof(efi_initrd_device_path.end), } }; static EFIAPI EFI_STATUS initrd_load_file( EFI_LOAD_FILE_PROTOCOL *this, EFI_DEVICE_PATH *file_path, bool boot_policy, size_t *buffer_size, void *buffer) { struct initrd_loader *loader; if (!this || !buffer_size || !file_path) return EFI_INVALID_PARAMETER; if (boot_policy) return EFI_UNSUPPORTED; loader = (struct initrd_loader *) this; if (loader->length == 0 || !loader->address) return EFI_NOT_FOUND; if (!buffer || *buffer_size < loader->length) { *buffer_size = loader->length; return EFI_BUFFER_TOO_SMALL; } memcpy(buffer, loader->address, loader->length); *buffer_size = loader->length; return EFI_SUCCESS; } EFI_STATUS initrd_register( const void *initrd_address, size_t initrd_length, EFI_HANDLE *ret_initrd_handle) { EFI_STATUS err; EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path; EFI_HANDLE handle; struct initrd_loader *loader; assert(ret_initrd_handle); if (!initrd_address || initrd_length == 0) return EFI_SUCCESS; /* check if a LINUX_INITRD_MEDIA_GUID DevicePath is already registered. LocateDevicePath checks for the "closest DevicePath" and returns its handle, where as InstallMultipleProtocolInterfaces only matches identical DevicePaths. */ err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), &dp, &handle); if (err != EFI_NOT_FOUND) /* InitrdMedia is already registered */ return EFI_ALREADY_STARTED; loader = xnew(struct initrd_loader, 1); *loader = (struct initrd_loader) { .load_file.LoadFile = initrd_load_file, .address = initrd_address, .length = initrd_length }; /* create a new handle and register the LoadFile2 protocol with the InitrdMediaPath on it */ err = BS->InstallMultipleProtocolInterfaces( ret_initrd_handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), &efi_initrd_device_path, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), loader, NULL); if (err != EFI_SUCCESS) free(loader); return err; } EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle) { EFI_STATUS err; struct initrd_loader *loader; if (!initrd_handle) return EFI_SUCCESS; /* get the LoadFile2 protocol that we allocated earlier */ err = BS->HandleProtocol(initrd_handle, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), (void **) &loader); if (err != EFI_SUCCESS) return err; /* uninstall all protocols thus destroying the handle */ err = BS->UninstallMultipleProtocolInterfaces( initrd_handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), &efi_initrd_device_path, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), loader, NULL); if (err != EFI_SUCCESS) return err; initrd_handle = NULL; free(loader); return EFI_SUCCESS; } ubustub-1/linux.c000066400000000000000000000131241504315023600142100ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Generic Linux boot protocol using the EFI/PE entry point of the kernel. Passes * initrd with the LINUX_INITRD_MEDIA_GUID DevicePath and cmdline with * EFI LoadedImageProtocol. * * This method works for Linux 5.8 and newer on ARM/Aarch64, x86/x68_64 and RISC-V. */ #include "efi-log.h" #include "initrd.h" #include "linux.h" #include "pe.h" #include "proto/device-path.h" #include "proto/loaded-image.h" #include "secure-boot.h" #include "util.h" #define STUB_PAYLOAD_GUID \ { 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } } typedef struct { const void *addr; size_t len; const EFI_DEVICE_PATH *device_path; } ValidationContext; static bool validate_payload( const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) { const ValidationContext *payload = ASSERT_PTR(ctx); if (device_path != payload->device_path) return false; /* Security arch (1) protocol does not provide a file buffer. Instead we are supposed to fetch the payload * ourselves, which is not needed as we already have everything in memory and the device paths match. */ if (file_buffer && (file_buffer != payload->addr || file_size != payload->len)) return false; return true; } static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len, EFI_HANDLE *ret_image) { assert(parent); assert(source); assert(ret_image); /* We could pass a NULL device path, but it's nicer to provide something and it allows us to identify * the loaded image from within the security hooks. */ struct { VENDOR_DEVICE_PATH payload; EFI_DEVICE_PATH end; } _packed_ payload_device_path = { .payload = { .Header = { .Type = MEDIA_DEVICE_PATH, .SubType = MEDIA_VENDOR_DP, .Length = sizeof(payload_device_path.payload), }, .Guid = STUB_PAYLOAD_GUID, }, .end = { .Type = END_DEVICE_PATH_TYPE, .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, .Length = sizeof(payload_device_path.end), }, }; /* We want to support unsigned kernel images as payload, which is safe to do under secure boot * because it is embedded in this stub loader (and since it is already running it must be trusted). */ install_security_override( validate_payload, &(ValidationContext) { .addr = source, .len = len, .device_path = &payload_device_path.payload.Header, }); EFI_STATUS ret = BS->LoadImage( /*BootPolicy=*/false, parent, &payload_device_path.payload.Header, (void *) source, len, ret_image); uninstall_security_override(); return ret; } EFI_STATUS linux_exec( EFI_HANDLE parent, const char16_t *cmdline, const struct iovec *kernel, const struct iovec *initrd) { size_t kernel_size_in_memory = 0; uint32_t compat_entry_point, entry_point; uint64_t image_base; EFI_STATUS err; assert(parent); assert(iovec_is_set(kernel)); assert(iovec_is_valid(initrd)); err = pe_kernel_info(kernel->iov_base, &entry_point, &compat_entry_point, &image_base, &kernel_size_in_memory); if (err == EFI_UNSUPPORTED) return log_error_status(err, "EFI_UNSUPPORTED: %m"); if (err != EFI_SUCCESS) return log_error_status(err, "Bad kernel image: %m"); _cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL; err = load_image(parent, kernel->iov_base, kernel->iov_len, &kernel_image); if (err != EFI_SUCCESS) return log_error_status(err, "Error loading kernel image: %m"); EFI_LOADED_IMAGE_PROTOCOL *loaded_image; err = BS->HandleProtocol( kernel_image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image); if (err != EFI_SUCCESS) return log_error_status(err, "Error getting kernel loaded image protocol: %m"); if (cmdline) { loaded_image->LoadOptions = (void *) cmdline; loaded_image->LoadOptionsSize = strsize16(loaded_image->LoadOptions); } _cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL; err = initrd_register(initrd->iov_base, initrd->iov_len, &initrd_handle); if (err != EFI_SUCCESS) return log_error_status(err, "Error registering initrd: %m"); log_wait(); err = BS->StartImage(kernel_image, NULL, NULL); /* Try calling the kernel compat entry point if one exists. */ if (err == EFI_UNSUPPORTED && compat_entry_point > 0) { EFI_IMAGE_ENTRY_POINT compat_entry = (EFI_IMAGE_ENTRY_POINT) ((uint8_t *) loaded_image->ImageBase + compat_entry_point); err = compat_entry(kernel_image, ST); } return log_error_status(err, "Error starting kernel image: %m"); } ubustub-1/part-discovery.c000066400000000000000000000252261504315023600160320ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-path-util.h" #include "part-discovery.h" #include "proto/block-io.h" #include "proto/device-path.h" #include "util.h" typedef struct { EFI_GUID PartitionTypeGUID; EFI_GUID UniquePartitionGUID; EFI_LBA StartingLBA; EFI_LBA EndingLBA; uint64_t Attributes; char16_t PartitionName[36]; } EFI_PARTITION_ENTRY; typedef struct { EFI_TABLE_HEADER Header; EFI_LBA MyLBA; EFI_LBA AlternateLBA; EFI_LBA FirstUsableLBA; EFI_LBA LastUsableLBA; EFI_GUID DiskGUID; EFI_LBA PartitionEntryLBA; uint32_t NumberOfPartitionEntries; uint32_t SizeOfPartitionEntry; uint32_t PartitionEntryArrayCRC32; uint8_t _pad[420]; } _packed_ GptHeader; assert_cc(sizeof(GptHeader) == 512); static bool verify_gpt(/*const*/ GptHeader *h, EFI_LBA lba_expected) { uint32_t crc32, crc32_saved; EFI_STATUS err; assert(h); /* Some superficial validation of the GPT header */ if (memcmp(&h->Header.Signature, "EFI PART", sizeof(h->Header.Signature)) != 0) return false; if (h->Header.HeaderSize < 92 || h->Header.HeaderSize > 512) return false; if (h->Header.Revision != 0x00010000U) return false; /* Calculate CRC check */ crc32_saved = h->Header.CRC32; h->Header.CRC32 = 0; err = BS->CalculateCrc32(h, h->Header.HeaderSize, &crc32); h->Header.CRC32 = crc32_saved; if (err != EFI_SUCCESS || crc32 != crc32_saved) return false; if (h->MyLBA != lba_expected) return false; if ((h->SizeOfPartitionEntry % sizeof(EFI_PARTITION_ENTRY)) != 0) return false; if (h->NumberOfPartitionEntries <= 0 || h->NumberOfPartitionEntries > 1024) return false; /* overflow check */ if (h->SizeOfPartitionEntry > SIZE_MAX / h->NumberOfPartitionEntries) return false; return true; } static EFI_STATUS try_gpt( const EFI_GUID *type, EFI_BLOCK_IO_PROTOCOL *block_io, EFI_LBA lba, EFI_LBA *ret_backup_lba, /* May be changed even on error! */ HARDDRIVE_DEVICE_PATH *ret_hd) { _cleanup_free_ EFI_PARTITION_ENTRY *entries = NULL; GptHeader gpt; EFI_STATUS err; uint32_t crc32; size_t size; assert(block_io); assert(ret_hd); /* Read the GPT header */ err = block_io->ReadBlocks( block_io, block_io->Media->MediaId, lba, sizeof(gpt), &gpt); if (err != EFI_SUCCESS) return err; /* Indicate the location of backup LBA even if the rest of the header is corrupt. */ if (ret_backup_lba) *ret_backup_lba = gpt.AlternateLBA; if (!verify_gpt(&gpt, lba)) return EFI_NOT_FOUND; /* Now load the GPT entry table */ size = ALIGN_TO((size_t) gpt.SizeOfPartitionEntry * (size_t) gpt.NumberOfPartitionEntries, 512); entries = xmalloc(size); err = block_io->ReadBlocks( block_io, block_io->Media->MediaId, gpt.PartitionEntryLBA, size, entries); if (err != EFI_SUCCESS) return err; /* Calculate CRC of entries array, too */ err = BS->CalculateCrc32(entries, size, &crc32); if (err != EFI_SUCCESS || crc32 != gpt.PartitionEntryArrayCRC32) return EFI_CRC_ERROR; /* Now we can finally look for xbootloader partitions. */ for (size_t i = 0; i < gpt.NumberOfPartitionEntries; i++) { EFI_PARTITION_ENTRY *entry = (EFI_PARTITION_ENTRY *) ((uint8_t *) entries + gpt.SizeOfPartitionEntry * i); if (!efi_guid_equal(&entry->PartitionTypeGUID, type)) continue; if (entry->EndingLBA < entry->StartingLBA) /* Bogus? */ continue; *ret_hd = (HARDDRIVE_DEVICE_PATH) { .Header = { .Type = MEDIA_DEVICE_PATH, .SubType = MEDIA_HARDDRIVE_DP, .Length = sizeof(HARDDRIVE_DEVICE_PATH), }, .PartitionNumber = i + 1, .PartitionStart = entry->StartingLBA, .PartitionSize = entry->EndingLBA - entry->StartingLBA + 1, .MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER, .SignatureType = SIGNATURE_TYPE_GUID, }; memcpy(ret_hd->Signature, &entry->UniquePartitionGUID, sizeof(ret_hd->Signature)); return EFI_SUCCESS; } /* This GPT was fully valid, but we didn't find what we are looking for. This * means there's no reason to check the second copy of the GPT header */ return EFI_NOT_FOUND; } static EFI_STATUS find_device(const EFI_GUID *type, EFI_HANDLE *device, EFI_DEVICE_PATH **ret_device_path) { EFI_STATUS err; assert(device); assert(ret_device_path); EFI_DEVICE_PATH *partition_path; err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &partition_path); if (err != EFI_SUCCESS) return err; /* Find the (last) partition node itself. */ EFI_DEVICE_PATH *part_node = NULL; for (EFI_DEVICE_PATH *node = partition_path; !device_path_is_end(node); node = device_path_next_node(node)) { if (node->Type != MEDIA_DEVICE_PATH || node->SubType != MEDIA_HARDDRIVE_DP) continue; part_node = node; } if (!part_node) return EFI_NOT_FOUND; /* Chop off the partition part, leaving us with the full path to the disk itself. */ _cleanup_free_ EFI_DEVICE_PATH *disk_path = NULL; EFI_DEVICE_PATH *p = disk_path = device_path_replace_node(partition_path, part_node, NULL); EFI_HANDLE disk_handle; EFI_BLOCK_IO_PROTOCOL *block_io; err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL), &p, &disk_handle); if (err != EFI_SUCCESS) return err; /* The drivers for other partitions on this drive may not be initialized on fastboot firmware, so we * have to ask the firmware to do just that. */ (void) BS->ConnectController(disk_handle, NULL, NULL, true); err = BS->HandleProtocol(disk_handle, MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL), (void **) &block_io); if (err != EFI_SUCCESS) return err; /* Filter out some block devices early. (We only care about block devices that aren't * partitions themselves — we look for GPT partition tables to parse after all —, and only * those which contain a medium and have at least 2 blocks.) */ if (block_io->Media->LogicalPartition || !block_io->Media->MediaPresent || block_io->Media->LastBlock <= 1) return EFI_NOT_FOUND; /* Try several copies of the GPT header, in case one is corrupted */ EFI_LBA backup_lba = 0; for (size_t nr = 0; nr < 3; nr++) { EFI_LBA lba; /* Read the first copy at LBA 1 and then try the backup GPT header pointed * to by the first header if that one was corrupted. As a last resort, * try the very last LBA of this block device. */ if (nr == 0) lba = 1; else if (nr == 1 && backup_lba != 0) lba = backup_lba; else if (nr == 2 && backup_lba != block_io->Media->LastBlock) lba = block_io->Media->LastBlock; else continue; HARDDRIVE_DEVICE_PATH hd; err = try_gpt(type, block_io, lba, nr == 0 ? &backup_lba : NULL, /* Only get backup LBA location from first GPT header. */ &hd); if (err != EFI_SUCCESS) { /* GPT was valid but no XBOOT loader partition found. */ if (err == EFI_NOT_FOUND) break; /* Bad GPT, try next one. */ continue; } /* Patch in the data we found */ *ret_device_path = device_path_replace_node(partition_path, part_node, &hd.Header); return EFI_SUCCESS; } /* No xbootloader partition found */ return EFI_NOT_FOUND; } EFI_STATUS partition_open(const EFI_GUID *type, EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir) { _cleanup_free_ EFI_DEVICE_PATH *partition_path = NULL; EFI_HANDLE new_device; EFI_FILE *root_dir; EFI_STATUS err; assert(type); assert(device); assert(ret_root_dir); err = find_device(type, device, &partition_path); if (err != EFI_SUCCESS) return err; EFI_DEVICE_PATH *dp = partition_path; err = BS->LocateDevicePath(MAKE_GUID_PTR(EFI_BLOCK_IO_PROTOCOL), &dp, &new_device); if (err != EFI_SUCCESS) return err; err = open_volume(new_device, &root_dir); if (err != EFI_SUCCESS) return err; if (ret_device) *ret_device = new_device; *ret_root_dir = root_dir; return EFI_SUCCESS; } char16_t *disk_get_part_uuid(EFI_HANDLE *handle) { EFI_STATUS err; EFI_DEVICE_PATH *dp; /* export the device path this image is started from */ if (!handle) return NULL; err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp); if (err != EFI_SUCCESS) return NULL; for (; !device_path_is_end(dp); dp = device_path_next_node(dp)) { if (dp->Type != MEDIA_DEVICE_PATH || dp->SubType != MEDIA_HARDDRIVE_DP) continue; HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *) dp; if (hd->SignatureType != SIGNATURE_TYPE_GUID) continue; return xasprintf(GUID_FORMAT_STR, GUID_FORMAT_VAL(hd->SignatureGuid)); } return NULL; } ubustub-1/pe.c000066400000000000000000000617131504315023600134640ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "chid.h" #include "devicetree.h" #include "efi-firmware.h" #include "efi-log.h" #include "pe.h" #include "util.h" #include "proto/dt-fixup.h" #define DOS_FILE_MAGIC "MZ" #define PE_FILE_MAGIC "PE\0\0" #if defined(__i386__) # define TARGET_MACHINE_TYPE 0x014CU # define TARGET_MACHINE_TYPE_COMPATIBILITY 0x8664U #elif defined(__x86_64__) # define TARGET_MACHINE_TYPE 0x8664U #elif defined(__aarch64__) # define TARGET_MACHINE_TYPE 0xAA64U #elif defined(__arm__) # define TARGET_MACHINE_TYPE 0x01C2U #elif defined(__riscv) && __riscv_xlen == 32 # define TARGET_MACHINE_TYPE 0x5032U #elif defined(__riscv) && __riscv_xlen == 64 # define TARGET_MACHINE_TYPE 0x5064U #elif defined(__loongarch__) && __loongarch_grlen == 32 # define TARGET_MACHINE_TYPE 0x6232U #elif defined(__loongarch__) && __loongarch_grlen == 64 # define TARGET_MACHINE_TYPE 0x6264U #else # error Unknown EFI arch #endif #ifndef TARGET_MACHINE_TYPE_COMPATIBILITY # define TARGET_MACHINE_TYPE_COMPATIBILITY 0 #endif typedef struct DosFileHeader { uint8_t Magic[2]; uint16_t LastSize; uint16_t nBlocks; uint16_t nReloc; uint16_t HdrSize; uint16_t MinAlloc; uint16_t MaxAlloc; uint16_t ss; uint16_t sp; uint16_t Checksum; uint16_t ip; uint16_t cs; uint16_t RelocPos; uint16_t nOverlay; uint16_t reserved[4]; uint16_t OEMId; uint16_t OEMInfo; uint16_t reserved2[10]; uint32_t ExeHeader; } _packed_ DosFileHeader; typedef struct CoffFileHeader { uint16_t Machine; uint16_t NumberOfSections; uint32_t TimeDateStamp; uint32_t PointerToSymbolTable; uint32_t NumberOfSymbols; uint16_t SizeOfOptionalHeader; uint16_t Characteristics; } _packed_ CoffFileHeader; #define OPTHDR32_MAGIC 0x10B /* PE32 OptionalHeader */ #define OPTHDR64_MAGIC 0x20B /* PE32+ OptionalHeader */ typedef struct PeImageDataDirectory { uint32_t VirtualAddress; uint32_t Size; } _packed_ PeImageDataDirectory; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 typedef struct PeOptionalHeader { uint16_t Magic; uint8_t LinkerMajor; uint8_t LinkerMinor; uint32_t SizeOfCode; uint32_t SizeOfInitializedData; uint32_t SizeOfUninitializeData; uint32_t AddressOfEntryPoint; uint32_t BaseOfCode; union { struct { /* PE32 */ uint32_t BaseOfData; uint32_t ImageBase32; }; uint64_t ImageBase64; /* PE32+ */ }; uint32_t SectionAlignment; uint32_t FileAlignment; uint16_t MajorOperatingSystemVersion; uint16_t MinorOperatingSystemVersion; uint16_t MajorImageVersion; uint16_t MinorImageVersion; uint16_t MajorSubsystemVersion; uint16_t MinorSubsystemVersion; uint32_t Win32VersionValue; uint32_t SizeOfImage; uint32_t SizeOfHeaders; uint32_t CheckSum; uint16_t Subsystem; uint16_t DllCharacteristics; union { struct { uint64_t SizeOfStackReserve64; uint64_t SizeOfStackCommit64; uint64_t SizeOfHeapReserve64; uint64_t SizeOfHeapCommit64; uint32_t LoaderFlags64; uint32_t NumberOfRvaAndSizes64; PeImageDataDirectory DataDirectory64[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; struct { uint32_t SizeOfStackReserve32; uint32_t SizeOfStackCommit32; uint32_t SizeOfHeapReserve32; uint32_t SizeOfHeapCommit32; uint32_t LoaderFlags32; uint32_t NumberOfRvaAndSizes32; PeImageDataDirectory DataDirectory32[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; }; } _packed_ PeOptionalHeader; typedef struct PeFileHeader { uint8_t Magic[4]; CoffFileHeader FileHeader; PeOptionalHeader OptionalHeader; } _packed_ PeFileHeader; #define SECTION_TABLE_BYTES_MAX (16U * 1024U * 1024U) static bool verify_dos(const DosFileHeader *dos) { assert(dos); DISABLE_WARNING_TYPE_LIMITS; return memcmp(dos->Magic, DOS_FILE_MAGIC, STRLEN(DOS_FILE_MAGIC)) == 0 && dos->ExeHeader >= sizeof(DosFileHeader) && (size_t) dos->ExeHeader <= SIZE_MAX - sizeof(PeFileHeader); REENABLE_WARNING; } static bool verify_pe( const DosFileHeader *dos, const PeFileHeader *pe, bool allow_compatibility) { assert(dos); assert(pe); return memcmp(pe->Magic, PE_FILE_MAGIC, STRLEN(PE_FILE_MAGIC)) == 0 && (pe->FileHeader.Machine == TARGET_MACHINE_TYPE || (allow_compatibility && pe->FileHeader.Machine == TARGET_MACHINE_TYPE_COMPATIBILITY)) && pe->FileHeader.NumberOfSections > 0 && IN_SET(pe->OptionalHeader.Magic, OPTHDR32_MAGIC, OPTHDR64_MAGIC) && pe->FileHeader.SizeOfOptionalHeader < SIZE_MAX - (dos->ExeHeader + offsetof(PeFileHeader, OptionalHeader)); } static size_t section_table_offset(const DosFileHeader *dos, const PeFileHeader *pe) { assert(dos); assert(pe); return dos->ExeHeader + offsetof(PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader; } static bool pe_section_name_equal(const char *a, const char *b) { if (a == b) return true; if (!a != !b) return false; /* Compares up to 8 characters of a and b i.e. the name size limit in the PE section header */ for (size_t i = 0; i < sizeof_field(PeSectionHeader, Name); i++) { if (a[i] != b[i]) return false; if (a[i] == 0) /* Name is shorter than 8 */ return true; } return true; } static bool pe_use_this_dtb( const void *dtb, size_t dtb_size, const void *base, const Device *device, size_t section_nb) { assert(dtb); EFI_STATUS err; /* Do nothing if a firmware dtb exists */ const void *fw_dtb = find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE)); if (fw_dtb) return false; /* There's nothing to match against if there is no .hwids section */ if (!device || !base) return false; const char *compatible = device_get_compatible(base, device); if (!compatible) return false; err = devicetree_match_by_compatible(dtb, dtb_size, compatible); if (err == EFI_SUCCESS) { log_debug("found device-tree based on HWID: %s", devicetree_get_compatible(dtb)); return true; } if (err == EFI_INVALID_PARAMETER) log_error_status(err, "Found bad DT blob in PE section %zu", section_nb); return false; } static bool pe_use_this_firmware( const void *efifw, size_t efifw_size, const void *base, const Device *device, size_t section_nb) { assert(efifw); EFI_STATUS err; /* if there is no hwids section, there is nothing much we can do */ if (!device || !base) return false; const char *fwid = device_get_fwid(base, device); if (!fwid) return false; err = efi_firmware_match_by_fwid(efifw, efifw_size, fwid); if (err == EFI_SUCCESS) return true; if (err == EFI_INVALID_PARAMETER) log_error_status(err, "Found bad efifw blob in PE section %zu", section_nb); return false; } static void pe_locate_sections_internal( const PeSectionHeader section_table[], size_t n_section_table, const char *const section_names[], size_t validate_base, const void *device_table, const Device *device, PeSectionVector sections[]) { assert(section_table || n_section_table == 0); assert(section_names); assert(sections); /* Searches for the sections listed in 'sections[]' within the section table. Validates the resulted * data. If 'validate_base' is non-zero also takes base offset when loaded into memory into account for * checking for overflows. */ for (size_t i = 0; section_names[i]; i++) FOREACH_ARRAY(j, section_table, n_section_table) { if (!pe_section_name_equal((const char*) j->Name, section_names[i])) continue; /* Overflow check: ignore sections that are impossibly large, relative to the file * address for the section. */ size_t size_max = SIZE_MAX - j->PointerToRawData; if ((size_t) j->SizeOfRawData > size_max) continue; /* Overflow check: ignore sections that are impossibly large, given the virtual * address for the section */ size_max = SIZE_MAX - j->VirtualAddress; if ((size_t) j->VirtualSize > size_max) continue; /* 2nd overflow check: ignore sections that are impossibly large also taking the * loaded base into account. */ if (validate_base != 0) { if (validate_base > size_max) continue; size_max -= validate_base; if (j->VirtualAddress > size_max) continue; } /* Special handling for .dtbauto sections compared to plain .dtb */ if (pe_section_name_equal(section_names[i], ".dtbauto")) { /* .dtbauto sections require validate_base for matching */ if (!validate_base) break; if (!pe_use_this_dtb( (const uint8_t *) SIZE_TO_PTR(validate_base) + j->VirtualAddress, j->VirtualSize, device_table, device, (PTR_TO_SIZE(j) - PTR_TO_SIZE(section_table)) / sizeof(*j))) continue; } /* handle efifw section which works very much like .dtbauto */ if (pe_section_name_equal(section_names[i], ".efifw")) { /* can't match without validate_base */ if (!validate_base) break; if (!pe_use_this_firmware( (const uint8_t *) SIZE_TO_PTR(validate_base) + j->VirtualAddress, j->VirtualSize, device_table, device, (PTR_TO_SIZE(j) - PTR_TO_SIZE(section_table)) / sizeof(*j))) continue; } /* At this time, the sizes and offsets have been validated. Store them away */ sections[i] = (PeSectionVector) { .memory_size = j->VirtualSize, .memory_offset = j->VirtualAddress, /* VirtualSize can be bigger than SizeOfRawData when the section requires * uninitialized data. It can also be smaller than SizeOfRawData when there's * no need for uninitialized data as SizeOfRawData is aligned to * FileAlignment and VirtualSize isn't. The actual data that's read from disk * is the minimum of these two fields. */ .file_size = MIN(j->SizeOfRawData, j->VirtualSize), .file_offset = j->PointerToRawData, }; /* First matching section wins, ignore the rest */ break; } } static bool looking_for_dtbauto(const char *const section_names[]) { assert(section_names); for (size_t i = 0; section_names[i]; i++) if (pe_section_name_equal(section_names[i], ".dtbauto")) return true; return false; } void pe_locate_sections( const PeSectionHeader section_table[], size_t n_section_table, const char *const section_names[], size_t validate_base, PeSectionVector sections[]) { if (!looking_for_dtbauto(section_names)) return pe_locate_sections_internal( section_table, n_section_table, section_names, validate_base, /* device_base */ NULL, /* device */ NULL, sections); /* It doesn't make sense not to provide validate_base here */ assert(validate_base != 0); const void *hwids = NULL; const Device *device = NULL; if (!firmware_devicetree_exists()) { /* Find HWIDs table and search for the current device */ static const char *const hwid_section_names[] = { ".hwids", NULL }; PeSectionVector hwids_section[1] = {}; pe_locate_sections_internal( section_table, n_section_table, hwid_section_names, validate_base, /* device_table */ NULL, /* device */ NULL, hwids_section); if (PE_SECTION_VECTOR_IS_SET(hwids_section)) { hwids = (const uint8_t *) SIZE_TO_PTR(validate_base) + hwids_section[0].memory_offset; EFI_STATUS err = chid_match(hwids, hwids_section[0].memory_size, DEVICE_TYPE_DEVICETREE, &device); if (err != EFI_SUCCESS) { log_error_status(err, "HWID matching failed, no DT blob will be selected: %m"); hwids = NULL; } } } return pe_locate_sections_internal( section_table, n_section_table, section_names, validate_base, hwids, device, sections); } static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) { /* The kernel may provide alternative PE entry points for different PE architectures. This allows * booting a 64-bit kernel on 32-bit EFI that is otherwise running on a 64-bit CPU. The locations of any * such compat entry points are located in a special PE section. */ assert(dos); assert(pe); static const char *const section_names[] = { ".compat", NULL }; PeSectionVector vector[1] = {}; pe_locate_sections( (const PeSectionHeader *) ((const uint8_t *) dos + section_table_offset(dos, pe)), pe->FileHeader.NumberOfSections, section_names, PTR_TO_SIZE(dos), vector); if (!PE_SECTION_VECTOR_IS_SET(vector)) /* not found */ return 0; typedef struct { uint8_t type; uint8_t size; uint16_t machine_type; uint32_t entry_point; } _packed_ LinuxPeCompat1; size_t addr = vector[0].memory_offset, size = vector[0].memory_size; while (size >= sizeof(LinuxPeCompat1) && addr % alignof(LinuxPeCompat1) == 0) { const LinuxPeCompat1 *compat = (const LinuxPeCompat1 *) ((const uint8_t *) dos + addr); if (compat->type == 0 || compat->size == 0 || compat->size > size) break; if (compat->type == 1 && compat->size >= sizeof(LinuxPeCompat1) && compat->machine_type == TARGET_MACHINE_TYPE) return compat->entry_point; addr += compat->size; size -= compat->size; } return 0; } EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_entry_point, uint32_t *ret_compat_entry_point, uint64_t *ret_image_base, size_t *ret_size_in_memory) { assert(base); const DosFileHeader *dos = (const DosFileHeader *) base; if (!verify_dos(dos)) return EFI_LOAD_ERROR; const PeFileHeader *pe = (const PeFileHeader *) ((const uint8_t *) base + dos->ExeHeader); if (!verify_pe(dos, pe, /* allow_compatibility= */ true)) return EFI_LOAD_ERROR; uint64_t image_base; switch (pe->OptionalHeader.Magic) { case OPTHDR32_MAGIC: image_base = pe->OptionalHeader.ImageBase32; break; case OPTHDR64_MAGIC: image_base = pe->OptionalHeader.ImageBase64; break; default: assert_not_reached(); } /* When allocating we need to also consider the virtual/uninitialized data sections, so parse it out * of the SizeOfImage field in the PE header and return it */ size_t size_in_memory = pe->OptionalHeader.SizeOfImage; /* Support for LINUX_INITRD_MEDIA_GUID was added in kernel stub 1.0. */ if (pe->OptionalHeader.MajorImageVersion < 1) return EFI_UNSUPPORTED; if (pe->FileHeader.Machine == TARGET_MACHINE_TYPE) { if (ret_entry_point) *ret_entry_point = pe->OptionalHeader.AddressOfEntryPoint; if (ret_compat_entry_point) *ret_compat_entry_point = 0; if (ret_image_base) *ret_image_base = image_base; if (ret_size_in_memory) *ret_size_in_memory = size_in_memory; return EFI_SUCCESS; } uint32_t compat_entry_point = get_compatibility_entry_address(dos, pe); if (compat_entry_point == 0) /* Image type not supported and no compat entry found. */ return EFI_UNSUPPORTED; if (ret_entry_point) *ret_entry_point = 0; if (ret_compat_entry_point) *ret_compat_entry_point = compat_entry_point; if (ret_image_base) *ret_image_base = image_base; if (ret_size_in_memory) *ret_size_in_memory = size_in_memory; return EFI_SUCCESS; } /* https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-data-directories-image-only */ #define BASE_RELOCATION_TABLE_DATA_DIRECTORY_ENTRY 5 /* We do not expect PE inner kernels to have any relocations. However that might be wrong for some * architectures, or it might change in the future. If the case of relocation arise, we should transform this * function in a function applying the relocations. However for now, since it would not be exercised and * would bitrot, we leave it as a check that relocations are never expected. */ EFI_STATUS pe_kernel_check_no_relocation(const void *base) { assert(base); const DosFileHeader *dos = base; if (!verify_dos(dos)) return EFI_LOAD_ERROR; const PeFileHeader *pe = (const PeFileHeader *) ((const uint8_t *) base + dos->ExeHeader); if (!verify_pe(dos, pe, /* allow_compatibility= */ true)) return EFI_LOAD_ERROR; const PeImageDataDirectory *data_directory; switch (pe->OptionalHeader.Magic) { case OPTHDR32_MAGIC: data_directory = pe->OptionalHeader.DataDirectory32; break; case OPTHDR64_MAGIC: data_directory = pe->OptionalHeader.DataDirectory64; break; default: assert_not_reached(); } if (data_directory[BASE_RELOCATION_TABLE_DATA_DIRECTORY_ENTRY].Size != 0) return log_error_status(EFI_LOAD_ERROR, "Inner kernel image contains base relocations, which we do not support."); return EFI_SUCCESS; } EFI_STATUS pe_section_table_from_base( const void *base, const PeSectionHeader **ret_section_table, size_t *ret_n_section_table) { assert(base); assert(ret_section_table); assert(ret_n_section_table); const DosFileHeader *dos = (const DosFileHeader*) base; if (!verify_dos(dos)) return EFI_LOAD_ERROR; const PeFileHeader *pe = (const PeFileHeader*) ((const uint8_t*) base + dos->ExeHeader); if (!verify_pe(dos, pe, /* allow_compatibility= */ false)) return EFI_LOAD_ERROR; *ret_section_table = (const PeSectionHeader*) ((const uint8_t*) base + section_table_offset(dos, pe)); *ret_n_section_table = pe->FileHeader.NumberOfSections; return EFI_SUCCESS; } EFI_STATUS pe_memory_locate_sections( const void *base, const char *const section_names[], PeSectionVector sections[]) { EFI_STATUS err; assert(base); assert(section_names); assert(sections); const PeSectionHeader *section_table; size_t n_section_table; err = pe_section_table_from_base(base, §ion_table, &n_section_table); if (err != EFI_SUCCESS) return err; pe_locate_sections( section_table, n_section_table, section_names, PTR_TO_SIZE(base), sections); return EFI_SUCCESS; } EFI_STATUS pe_section_table_from_file( EFI_FILE *handle, PeSectionHeader **ret_section_table, size_t *ret_n_section_table) { EFI_STATUS err; size_t len; assert(handle); assert(ret_section_table); assert(ret_n_section_table); DosFileHeader dos; len = sizeof(dos); err = handle->Read(handle, &len, &dos); if (err != EFI_SUCCESS) return err; if (len != sizeof(dos) || !verify_dos(&dos)) return EFI_LOAD_ERROR; err = handle->SetPosition(handle, dos.ExeHeader); if (err != EFI_SUCCESS) return err; PeFileHeader pe; len = sizeof(pe); err = handle->Read(handle, &len, &pe); if (err != EFI_SUCCESS) return err; if (len != sizeof(pe) || !verify_pe(&dos, &pe, /* allow_compatibility= */ false)) return EFI_LOAD_ERROR; DISABLE_WARNING_TYPE_LIMITS; if ((size_t) pe.FileHeader.NumberOfSections > SIZE_MAX / sizeof(PeSectionHeader)) return EFI_OUT_OF_RESOURCES; REENABLE_WARNING; size_t n_section_table = (size_t) pe.FileHeader.NumberOfSections; if (n_section_table * sizeof(PeSectionHeader) > SECTION_TABLE_BYTES_MAX) return EFI_OUT_OF_RESOURCES; _cleanup_free_ PeSectionHeader *section_table = xnew(PeSectionHeader, n_section_table); if (!section_table) return EFI_OUT_OF_RESOURCES; err = handle->SetPosition(handle, section_table_offset(&dos, &pe)); if (err != EFI_SUCCESS) return err; len = n_section_table * sizeof(PeSectionHeader); err = handle->Read(handle, &len, section_table); if (err != EFI_SUCCESS) return err; if (len != n_section_table * sizeof(PeSectionHeader)) return EFI_LOAD_ERROR; *ret_section_table = TAKE_PTR(section_table); *ret_n_section_table = n_section_table; return EFI_SUCCESS; } ubustub-1/random-seed.c000066400000000000000000000346651504315023600152640ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "efi-efivars.h" #include "efi-log.h" #include "memory-util-fundamental.h" #include "proto/rng.h" #include "random-seed.h" #include "secure-boot.h" #include "sha256.h" #include "util.h" #define RANDOM_MAX_SIZE_MIN (32U) #define RANDOM_MAX_SIZE_MAX (32U*1024U) struct linux_efi_random_seed { uint32_t size; uint8_t seed[]; }; #define LINUX_EFI_RANDOM_SEED_TABLE_GUID \ { 0x1ce1e5bc, 0x7ceb, 0x42f2, { 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b } } /* SHA256 gives us 256/8=32 bytes */ #define HASH_VALUE_SIZE 32 /* Linux's RNG is 256 bits, so let's provide this much */ #define DESIRED_SEED_SIZE 32 /* Some basic domain separation in case somebody uses this data elsewhere */ #define HASH_LABEL "systemd-boot random seed label v1" static EFI_STATUS acquire_rng(void *ret, size_t size) { EFI_RNG_PROTOCOL *rng; EFI_STATUS err; assert(ret); /* Try to acquire the specified number of bytes from the UEFI RNG */ err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_RNG_PROTOCOL), NULL, (void **) &rng); if (err != EFI_SUCCESS) return err; if (!rng) return EFI_UNSUPPORTED; err = rng->GetRNG(rng, NULL, size, ret); /* On some systems the RNG might not be ready during early boot, handle gracefully and don't log. */ if (err == EFI_NOT_READY) return err; if (err != EFI_SUCCESS) return log_warning_status(err, "Failed to acquire RNG data, proceeding without: %m"); return EFI_SUCCESS; } static EFI_STATUS acquire_system_token(void **ret, size_t *ret_size) { _cleanup_free_ char *data = NULL; EFI_STATUS err; size_t size; assert(ret); assert(ret_size); err = efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderSystemToken", (void**) &data, &size); if (err != EFI_SUCCESS) { if (err != EFI_NOT_FOUND) log_error_status(err, "Failed to read LoaderSystemToken EFI variable: %m"); return err; } if (size <= 0) return log_error_status(EFI_NOT_FOUND, "System token too short, ignoring."); *ret = TAKE_PTR(data); *ret_size = size; return EFI_SUCCESS; } static void validate_sha256(void) { #ifdef EFI_DEBUG /* Let's validate our SHA256 implementation. We stole it from glibc, and converted it to UEFI * style. We better check whether it does the right stuff. We use the simpler test vectors from the * SHA spec. Note that we strip this out in optimization builds. */ static const struct { const char *string; uint8_t hash[HASH_VALUE_SIZE]; } array[] = { { "abc", { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }}, { "", { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }}, { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }}, { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", { 0xcf, 0x5b, 0x16, 0xa7, 0x78, 0xaf, 0x83, 0x80, 0x03, 0x6c, 0xe5, 0x9e, 0x7b, 0x04, 0x92, 0x37, 0x0b, 0x24, 0x9b, 0x11, 0xe8, 0xf0, 0x7a, 0x51, 0xaf, 0xac, 0x45, 0x03, 0x7a, 0xfe, 0xe9, 0xd1 }}, }; FOREACH_ELEMENT(i, array) assert(memcmp(SHA256_DIRECT(i->string, strlen8(i->string)), i->hash, HASH_VALUE_SIZE) == 0); #endif } EFI_STATUS process_random_seed(EFI_FILE *root_dir) { uint8_t random_bytes[DESIRED_SEED_SIZE], hash_key[HASH_VALUE_SIZE]; _cleanup_free_ struct linux_efi_random_seed *new_seed_table = NULL; struct linux_efi_random_seed *previous_seed_table = NULL; _cleanup_free_ void *seed = NULL, *system_token = NULL; _cleanup_file_close_ EFI_FILE *handle = NULL; _cleanup_free_ EFI_FILE_INFO *info = NULL; struct sha256_ctx hash; uint64_t uefi_monotonic_counter = 0; size_t size, rsize, wsize; bool seeded_by_efi = false; EFI_STATUS err; EFI_TIME now; CLEANUP_ERASE(random_bytes); CLEANUP_ERASE(hash_key); CLEANUP_ERASE(hash); assert(root_dir); assert_cc(DESIRED_SEED_SIZE == HASH_VALUE_SIZE); validate_sha256(); /* hash = LABEL || sizeof(input1) || input1 || ... || sizeof(inputN) || inputN */ sha256_init_ctx(&hash); /* Some basic domain separation in case somebody uses this data elsewhere */ sha256_process_bytes(HASH_LABEL, sizeof(HASH_LABEL) - 1, &hash); previous_seed_table = find_configuration_table(MAKE_GUID_PTR(LINUX_EFI_RANDOM_SEED_TABLE)); if (!previous_seed_table) { size = 0; sha256_process_bytes(&size, sizeof(size), &hash); } else { size = previous_seed_table->size; seeded_by_efi = size >= DESIRED_SEED_SIZE; sha256_process_bytes(&size, sizeof(size), &hash); sha256_process_bytes(previous_seed_table->seed, size, &hash); /* Zero and free the previous seed table only at the end after we've managed to install a new * one, so that in case this function fails or aborts, Linux still receives whatever the * previous bootloader chain set. So, the next line of this block is not an explicit_bzero() * call. */ } /* Request some random data from the UEFI RNG. We don't need this to work safely, but it's a good * idea to use it because it helps us for cases where users mistakenly include a random seed in * golden master images that are replicated many times. */ err = acquire_rng(random_bytes, sizeof(random_bytes)); if (err != EFI_SUCCESS) { size = 0; /* If we can't get any randomness from EFI itself, then we'll only be relying on what's in * ESP. But ESP is mutable, so if secure boot is enabled, we probably shouldn't trust that * alone, in which case we bail out early. */ if (!seeded_by_efi && secure_boot_enabled()) return EFI_NOT_FOUND; } else { seeded_by_efi = true; size = sizeof(random_bytes); } sha256_process_bytes(&size, sizeof(size), &hash); sha256_process_bytes(random_bytes, size, &hash); /* Get some system specific seed that the installer might have placed in an EFI variable. We include * it in our hash. This is protection against golden master image sloppiness, and it remains on the * system, even when disk images are duplicated or swapped out. */ size = 0; err = acquire_system_token(&system_token, &size); if ((err != EFI_SUCCESS || size < DESIRED_SEED_SIZE) && !seeded_by_efi) return err; sha256_process_bytes(&size, sizeof(size), &hash); if (system_token) { sha256_process_bytes(system_token, size, &hash); explicit_bzero_safe(system_token, size); } err = root_dir->Open( root_dir, &handle, (char16_t *) u"\\loader\\random-seed", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0); if (err != EFI_SUCCESS) { if (!IN_SET(err, EFI_NOT_FOUND, EFI_WRITE_PROTECTED)) log_error_status(err, "Failed to open random seed file: %m"); return err; } err = get_file_info(handle, &info, NULL); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to get file info for random seed: %m"); size = info->FileSize; if (size < RANDOM_MAX_SIZE_MIN) return log_error("Random seed file is too short."); if (size > RANDOM_MAX_SIZE_MAX) return log_error("Random seed file is too large."); seed = xmalloc(size); rsize = size; err = handle->Read(handle, &rsize, seed); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to read random seed file: %m"); if (rsize != size) { explicit_bzero_safe(seed, rsize); return log_error_status(EFI_PROTOCOL_ERROR, "Short read on random seed file."); } sha256_process_bytes(&size, sizeof(size), &hash); sha256_process_bytes(seed, size, &hash); explicit_bzero_safe(seed, size); err = handle->SetPosition(handle, 0); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to seek to beginning of random seed file: %m"); /* Let's also include the UEFI monotonic counter (which is supposedly increasing on every single * boot) in the hash, so that even if the changes to the ESP for some reason should not be * persistent, the random seed we generate will still be different on every single boot. */ err = BS->GetNextMonotonicCount(&uefi_monotonic_counter); if (err != EFI_SUCCESS && !seeded_by_efi) return log_error_status(err, "Failed to acquire UEFI monotonic counter: %m"); size = sizeof(uefi_monotonic_counter); sha256_process_bytes(&size, sizeof(size), &hash); sha256_process_bytes(&uefi_monotonic_counter, size, &hash); err = RT->GetTime(&now, NULL); size = err == EFI_SUCCESS ? sizeof(now) : 0; /* Known to be flaky, so don't bark on error. */ sha256_process_bytes(&size, sizeof(size), &hash); sha256_process_bytes(&now, size, &hash); /* hash_key = HASH(hash) */ sha256_finish_ctx(&hash, hash_key); /* hash = hash_key || 0 */ sha256_init_ctx(&hash); sha256_process_bytes(hash_key, sizeof(hash_key), &hash); sha256_process_bytes(&(const uint8_t){ 0 }, sizeof(uint8_t), &hash); /* random_bytes = HASH(hash) */ sha256_finish_ctx(&hash, random_bytes); size = sizeof(random_bytes); /* If the file size is too large, zero out the remaining bytes on disk. */ if (size < info->FileSize) { err = handle->SetPosition(handle, size); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to seek to offset of random seed file: %m"); wsize = info->FileSize - size; err = handle->Write(handle, &wsize, seed /* All zeros now */); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to write random seed file: %m"); if (wsize != info->FileSize - size) return log_error_status(EFI_PROTOCOL_ERROR, "Short write on random seed file."); err = handle->Flush(handle); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to flush random seed file: %m"); err = handle->SetPosition(handle, 0); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to seek to beginning of random seed file: %m"); /* We could truncate the file here with something like: * * info->FileSize = size; * err = handle->SetInfo(handle, &GenericFileInfo, info->Size, info); * if (err != EFI_SUCCESS) * return log_error_status(err, "Failed to truncate random seed file: %u"); * * But this is considered slightly risky, because EFI filesystem drivers are a little bit * flimsy. So instead we rely on userspace eventually truncating this when it writes a new * seed. For now the best we do is zero it. */ } /* Update the random seed on disk before we use it */ wsize = size; err = handle->Write(handle, &wsize, random_bytes); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to write random seed file: %m"); if (wsize != size) return log_error_status(EFI_PROTOCOL_ERROR, "Short write on random seed file."); err = handle->Flush(handle); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to flush random seed file: %m"); err = BS->AllocatePool(EfiACPIReclaimMemory, offsetof(struct linux_efi_random_seed, seed) + DESIRED_SEED_SIZE, (void **) &new_seed_table); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to allocate EFI table for random seed: %m"); new_seed_table->size = DESIRED_SEED_SIZE; /* hash = hash_key || 1 */ sha256_init_ctx(&hash); sha256_process_bytes(hash_key, sizeof(hash_key), &hash); sha256_process_bytes(&(const uint8_t){ 1 }, sizeof(uint8_t), &hash); /* new_seed_table->seed = HASH(hash) */ sha256_finish_ctx(&hash, new_seed_table->seed); err = BS->InstallConfigurationTable(MAKE_GUID_PTR(LINUX_EFI_RANDOM_SEED_TABLE), new_seed_table); if (err != EFI_SUCCESS) return log_error_status(err, "Failed to install EFI table for random seed: %m"); TAKE_PTR(new_seed_table); if (previous_seed_table) { /* Now that we've succeeded in installing the new table, we can safely nuke the old one. */ explicit_bzero_safe(previous_seed_table->seed, previous_seed_table->size); explicit_bzero_safe(previous_seed_table, sizeof(*previous_seed_table)); free(previous_seed_table); } return EFI_SUCCESS; } ubustub-1/secure-boot.c000066400000000000000000000147401504315023600153050ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "console.h" #include "efi-efivars.h" #include "efi-log.h" #include "efi-string-table.h" #include "proto/security-arch.h" #include "secure-boot.h" #include "util.h" bool secure_boot_enabled(void) { bool secure = false; /* avoid false maybe-uninitialized warning */ EFI_STATUS err; err = efivar_get_boolean_u8(MAKE_GUID_PTR(EFI_GLOBAL_VARIABLE), u"SecureBoot", &secure); return err == EFI_SUCCESS && secure; } /* * Custom mode allows the secure boot certificate databases db, dbx, KEK, and PK to be changed without the variable * updates being signed. When enrolling certificates to an unconfigured system (no PK present yet) writing * db, dbx and KEK updates without signature works fine even in standard mode. Writing PK updates without * signature requires custom mode in any case. * * Enabling custom mode works only if a user is physically present. Note that OVMF has a dummy * implementation for the user presence check (there is no useful way to implement a presence check for a * virtual machine). * * FYI: Your firmware setup utility might offers the option to enroll certificates from *.crt files * (DER-encoded x509 certificates) on the ESP; that uses custom mode too. Your firmware setup might also * offer the option to switch the system into custom mode for the next boot. */ static bool custom_mode_enabled(void) { bool enabled = false; (void) efivar_get_boolean_u8(MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE), u"CustomMode", &enabled); return enabled; } static EFI_STATUS set_custom_mode(bool enable) { static char16_t name[] = u"CustomMode"; static uint32_t attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS; uint8_t mode = enable ? 1 /* CUSTOM_SECURE_BOOT_MODE */ : 0; /* STANDARD_SECURE_BOOT_MODE */ return RT->SetVariable(name, MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE), attr, sizeof(mode), &mode); } static struct SecurityOverride { EFI_SECURITY_ARCH_PROTOCOL *security; EFI_SECURITY2_ARCH_PROTOCOL *security2; EFI_SECURITY_FILE_AUTHENTICATION_STATE original_hook; EFI_SECURITY2_FILE_AUTHENTICATION original_hook2; security_validator_t validator; const void *validator_ctx; } security_override; static EFIAPI EFI_STATUS security_hook( const EFI_SECURITY_ARCH_PROTOCOL *this, uint32_t authentication_status, const EFI_DEVICE_PATH *file) { assert(security_override.validator); assert(security_override.security); assert(security_override.original_hook); if (security_override.validator(security_override.validator_ctx, file, NULL, 0)) return EFI_SUCCESS; return security_override.original_hook(security_override.security, authentication_status, file); } static EFIAPI EFI_STATUS security2_hook( const EFI_SECURITY2_ARCH_PROTOCOL *this, const EFI_DEVICE_PATH *device_path, void *file_buffer, size_t file_size, bool boot_policy) { assert(security_override.validator); assert(security_override.security2); assert(security_override.original_hook2); if (security_override.validator(security_override.validator_ctx, device_path, file_buffer, file_size)) return EFI_SUCCESS; return security_override.original_hook2( security_override.security2, device_path, file_buffer, file_size, boot_policy); } /* This replaces the platform provided security arch protocols hooks (defined in the UEFI Platform * Initialization Specification) with our own that uses the given validator to decide if a image is to be * trusted. If not running in secure boot or the protocols are not available nothing happens. The override * must be removed with uninstall_security_override() after LoadImage() has been called. * * This is a hack as we do not own the security protocol instances and modifying them is not an official part * of their spec. But there is little else we can do to circumvent secure boot short of implementing our own * PE loader. We could replace the firmware instances with our own instance using * ReinstallProtocolInterface(), but some firmware will still use the old ones. */ void install_security_override(security_validator_t validator, const void *validator_ctx) { EFI_STATUS err; assert(validator); if (!secure_boot_enabled()) return; security_override = (struct SecurityOverride) { .validator = validator, .validator_ctx = validator_ctx, }; EFI_SECURITY_ARCH_PROTOCOL *security = NULL; err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_SECURITY_ARCH_PROTOCOL), NULL, (void **) &security); if (err == EFI_SUCCESS) { security_override.security = security; security_override.original_hook = security->FileAuthenticationState; security->FileAuthenticationState = security_hook; } EFI_SECURITY2_ARCH_PROTOCOL *security2 = NULL; err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_SECURITY2_ARCH_PROTOCOL), NULL, (void **) &security2); if (err == EFI_SUCCESS) { security_override.security2 = security2; security_override.original_hook2 = security2->FileAuthentication; security2->FileAuthentication = security2_hook; } } void uninstall_security_override(void) { if (security_override.original_hook) security_override.security->FileAuthenticationState = security_override.original_hook; if (security_override.original_hook2) security_override.security2->FileAuthentication = security_override.original_hook2; } static const char *secure_boot_enroll_table[_SECURE_BOOT_ENROLL_MAX] = { [ENROLL_OFF] = "off", [ENROLL_MANUAL] = "manual", [ENROLL_IF_SAFE] = "if-safe", [ENROLL_FORCE] = "force" }; static const char *secure_boot_enroll_action_table[_SECURE_BOOT_ENROLL_ACTION_MAX] = { [ENROLL_ACTION_REBOOT] = "reboot", [ENROLL_ACTION_SHUTDOWN] = "shutdown" }; DEFINE_STRING_TABLE_LOOKUP_TO_STRING(secure_boot_enroll, secure_boot_enroll); DEFINE_STRING_TABLE_LOOKUP_TO_STRING(secure_boot_enroll_action, secure_boot_enroll_action); ubustub-1/sha1.c000066400000000000000000000232251504315023600137100ustar00rootroot00000000000000/* SPDX-License-Identifier: LicenseRef-alg-sha1-public-domain */ /* SHA-1 in C By Steve Reid 100% Public Domain ----------------- Modified 7/98 By James H. Brown Still 100% Public Domain Corrected a problem which generated improper hash values on 16 bit machines Routine SHA1Update changed from void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) to void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned long len) The 'len' parameter was declared an int which works fine on 32 bit machines. However, on 16 bit machines an int is too small for the shifts being done against it. This caused the hash function to generate incorrect values if len was greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). Since the file IO in main() reads 16K at a time, any file 8K or larger would be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million "a"s). I also changed the declaration of variables i & j in SHA1Update to unsigned long from unsigned int for the same reason. These changes should make no difference to any 32 bit implementations since an int and a long are the same size in those environments. -- I also corrected a few compiler warnings generated by Borland C. 1. Added #include for exit() prototype 2. Removed unused variable 'j' in SHA1Final 3. Changed exit(0) to return(0) at end of main. ALL changes I made can be located by searching for comments containing 'JHB' ----------------- Modified 8/98 By Steve Reid Still 100% public domain 1- Removed #include and used return() instead of exit() 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net ----------------- Modified 4/01 By Saul Kravitz Still 100% PD Modified to run on Compaq Alpha hardware. ----------------- Modified 07/2002 By Ralph Giles Still 100% public domain modified for use with stdint types, autoconf code cleanup, removed attribution comments switched SHA1Final() argument order for consistency use SHA1_ prefix for public api move public api to sha1.h ----------------- Modified 10/2017 By Björn Esser Still 100% public domain modified for use with libxcrypt Modified 09/2024 By anonymix007 <48598263+anonymix007@users.noreply.github.com> Still 100% public domain modified for use with systemd */ #include "efi-string.h" #include "memory-util-fundamental.h" #include "sha1.h" #define SHA1_DIGEST_SIZE 20 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ /* FIXME: can we do this in an endian-proof way? */ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define blk0(i) block.l[i] #else # define blk0(i) (block.l[i] = (rol(block.l[i], 24) & 0xFF00FF00) | (rol(block.l[i], 8) & 0x00FF00FF)) #endif #define blk(i) \ (block.l[i & 15] = rol( \ block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ \ block.l[i & 15], \ 1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R1(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R2(v, w, x, y, z, i) \ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ w = rol(w, 30); #define R3(v, w, x, y, z, i) \ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ w = rol(w, 30); #define R4(v, w, x, y, z, i) \ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ w = rol(w, 30); /* Hash a single 512-bit block. This is the core of the algorithm. */ static void sha1_do_transform(uint32_t state[5], const uint8_t buffer[64]) { uint32_t a, b, c, d, e; typedef union { uint8_t c[64]; uint32_t l[16]; } CHAR64LONG16; CHAR64LONG16 block; memcpy(&block, buffer, 64); /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void sha1_init_ctx(struct sha1_ctx *ctx) { /* SHA1 initialization constants */ ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; ctx->state[4] = 0xC3D2E1F0; ctx->count[0] = ctx->count[1] = 0; } /* Run your data through this. */ void sha1_process_bytes(const void *buffer, size_t size, struct sha1_ctx *ctx) { size_t i, j; j = (ctx->count[0] >> 3) & 63; if ((ctx->count[0] += (uint32_t) size << 3) < ((uint32_t) size << 3)) ctx->count[1]++; ctx->count[1] += (uint32_t) (size >> 29); if ((j + size) > 63) { memcpy(&ctx->buffer[j], buffer, (i = 64 - j)); sha1_do_transform(ctx->state, ctx->buffer); DISABLE_WARNING_STRINGOP_OVERREAD; for (; i + 63 < size; i += 64) sha1_do_transform(ctx->state, (const uint8_t *) buffer + i); REENABLE_WARNING; j = 0; } else i = 0; memcpy(&ctx->buffer[j], (const uint8_t *) buffer + i, size - i); } /* Add padding and return the message digest. */ void *sha1_finish_ctx(struct sha1_ctx *ctx, uint8_t result[static SHA1_DIGEST_SIZE]) { uint32_t i; uint8_t finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char) ((ctx->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ } sha1_process_bytes((const uint8_t *) "\200", 1, ctx); while ((ctx->count[0] & 504) != 448) sha1_process_bytes((const uint8_t *) "\0", 1, ctx); sha1_process_bytes(finalcount, 8, ctx); /* Should cause a sha1_do_transform() */ for (i = 0; i < SHA1_DIGEST_SIZE; i++) { result[i] = (uint8_t) ((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } /* Wipe variables */ i = 0; memzero(ctx, sizeof(struct sha1_ctx)); memzero(finalcount, 8); /* SWR */ return result; } ubustub-1/sha256.c000066400000000000000000000241521504315023600140640ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */ /* Functions to compute SHA256 message digest of files or memory blocks. according to the definition of SHA256 in FIPS 180-2. Copyright (C) 2007-2022 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #include "efi-string.h" #include "assert-fundamental.h" #include "memory-util-fundamental.h" #include "sha256.h" #include "unaligned-fundamental.h" #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define SWAP(n) \ __builtin_bswap32(n) # define SWAP64(n) \ __builtin_bswap64(n) #else # define SWAP(n) (n) # define SWAP64(n) (n) #endif /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (FIPS 180-2:5.1.1) */ static const uint8_t fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; /* Constants for SHA256 from FIPS 180-2:4.2.2. */ static const uint32_t K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; static void sha256_process_block(const void *, size_t, struct sha256_ctx *); /* Initialize structure containing state of computation. (FIPS 180-2:5.3.2) */ void sha256_init_ctx(struct sha256_ctx *ctx) { assert(ctx); ctx->H[0] = 0x6a09e667; ctx->H[1] = 0xbb67ae85; ctx->H[2] = 0x3c6ef372; ctx->H[3] = 0xa54ff53a; ctx->H[4] = 0x510e527f; ctx->H[5] = 0x9b05688c; ctx->H[6] = 0x1f83d9ab; ctx->H[7] = 0x5be0cd19; ctx->total64 = 0; ctx->buflen = 0; } /* Process the remaining bytes in the internal buffer and the usual prolog according to the standard and write the result to RESBUF. */ uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]) { /* Take yet unprocessed bytes into account. */ uint32_t bytes = ctx->buflen; size_t pad; assert(ctx); assert(resbuf); /* Now count remaining bytes. */ ctx->total64 += bytes; pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; memcpy(&ctx->buffer[bytes], fillbuf, pad); /* Put the 64-bit file length in *bits* at the end of the buffer. */ ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3); ctx->buffer32[(bytes + pad) / 4] = SWAP((ctx->total[TOTAL64_high] << 3) | (ctx->total[TOTAL64_low] >> 29)); /* Process last bytes. */ sha256_process_block(ctx->buffer, bytes + pad + 8, ctx); /* Put result from CTX in first 32 bytes following RESBUF. */ for (size_t i = 0; i < 8; ++i) unaligned_write_ne32(resbuf + i * sizeof(uint32_t), SWAP(ctx->H[i])); return resbuf; } void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx) { assert(buffer); assert(ctx); /* When we already have some bits in our internal buffer concatenate both inputs first. */ if (ctx->buflen != 0) { size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over; memcpy(&ctx->buffer[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 64) { sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx); ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen); } buffer = (const char *) buffer + add; len -= add; } /* Process available complete blocks. */ if (len >= 64) { if (IS_ALIGNED32(buffer)) { sha256_process_block(buffer, len & ~63, ctx); buffer = (const char *) buffer + (len & ~63); len &= 63; } else while (len > 64) { memcpy(ctx->buffer, buffer, 64); sha256_process_block(ctx->buffer, 64, ctx); buffer = (const char *) buffer + 64; len -= 64; } } /* Move remaining bytes into internal buffer. */ if (len > 0) { size_t left_over = ctx->buflen; memcpy(&ctx->buffer[left_over], buffer, len); left_over += len; if (left_over >= 64) { sha256_process_block(ctx->buffer, 64, ctx); left_over -= 64; memcpy(ctx->buffer, &ctx->buffer[64], left_over); } ctx->buflen = left_over; } } /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 64 == 0. */ static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) { const uint32_t *words = ASSERT_PTR(buffer); size_t nwords = len / sizeof(uint32_t); assert(ctx); uint32_t a = ctx->H[0]; uint32_t b = ctx->H[1]; uint32_t c = ctx->H[2]; uint32_t d = ctx->H[3]; uint32_t e = ctx->H[4]; uint32_t f = ctx->H[5]; uint32_t g = ctx->H[6]; uint32_t h = ctx->H[7]; /* First increment the byte count. FIPS 180-2 specifies the possible length of the file up to 2^64 bits. Here we only compute the number of bytes. */ ctx->total64 += len; /* Process all bytes in the buffer with 64 bytes in each round of the loop. */ while (nwords > 0) { uint32_t W[64]; uint32_t a_save = a; uint32_t b_save = b; uint32_t c_save = c; uint32_t d_save = d; uint32_t e_save = e; uint32_t f_save = f; uint32_t g_save = g; uint32_t h_save = h; /* Operators defined in FIPS 180-2:4.1.2. */ #define Ch(x, y, z) ((x & y) ^ (~x & z)) #define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22)) #define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25)) #define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3)) #define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10)) /* It is unfortunate that C does not provide an operator for cyclic rotation. Hope the C compiler is smart enough. */ #define CYCLIC(w, s) ((w >> s) | (w << (32 - s))) /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ for (size_t t = 0; t < 16; ++t) { W[t] = SWAP (*words); ++words; } for (size_t t = 16; t < 64; ++t) W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16]; /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ for (size_t t = 0; t < 64; ++t) { uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t]; uint32_t T2 = S0 (a) + Maj (a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } /* Add the starting values of the context according to FIPS 180-2:6.2.2 step 4. */ a += a_save; b += b_save; c += c_save; d += d_save; e += e_save; f += f_save; g += g_save; h += h_save; /* Prepare for the next round. */ nwords -= 16; } /* Put checksum in context given as argument. */ ctx->H[0] = a; ctx->H[1] = b; ctx->H[2] = c; ctx->H[3] = d; ctx->H[4] = e; ctx->H[5] = f; ctx->H[6] = g; ctx->H[7] = h; } uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]) { struct sha256_ctx ctx; sha256_init_ctx(&ctx); sha256_process_bytes(buffer, sz, &ctx); return sha256_finish_ctx(&ctx, result); } ubustub-1/shim.c000066400000000000000000000120771504315023600140170ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Port to systemd-boot * Copyright © 2017 Max Resch * * Security Policy Handling * Copyright © 2012 * https://github.com/mjg59/efitools */ #include "device-path-util.h" #include "efi-efivars.h" #include "secure-boot.h" #include "shim.h" #include "util.h" #if defined(__x86_64__) || defined(__i386__) #define __sysv_abi__ __attribute__((sysv_abi)) #else #define __sysv_abi__ #endif struct ShimLock { EFI_STATUS __sysv_abi__ (*shim_verify) (const void *buffer, uint32_t size); /* context is actually a struct for the PE header, but it isn't needed so void is sufficient just do define the interface * see shim.c/shim.h and PeHeader.h in the github shim repo */ EFI_STATUS __sysv_abi__ (*generate_hash) (void *data, uint32_t datasize, void *context, uint8_t *sha256hash, uint8_t *sha1hash); EFI_STATUS __sysv_abi__ (*read_header) (void *data, uint32_t datasize, void *context); }; #define SHIM_LOCK_GUID \ { 0x605dab50, 0xe046, 0x4300, { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } } #define SHIM_IMAGE_LOADER_GUID \ { 0x1f492041, 0xfadb, 0x4e59, { 0x9e, 0x57, 0x7c, 0xaf, 0xe7, 0x3a, 0x55, 0xab } } bool shim_loaded(void) { struct ShimLock *shim_lock; return BS->LocateProtocol(MAKE_GUID_PTR(SHIM_LOCK), NULL, (void **) &shim_lock) == EFI_SUCCESS; } /* The shim lock protocol is for pre-v16 shim, where it was not hooked up to the BS->LoadImage() system * table and friends, and it has to be checked manually via the shim_validate() helper. If the shim image * loader protocol is available (shim v16 and newer), then it will have overridden BS->LoadImage() and * friends in the system table, so no specific helper is needed, and the standard BS->LoadImage() and * friends can be called instead. */ bool shim_loader_available(void) { void *shim_image_loader; return BS->LocateProtocol(MAKE_GUID_PTR(SHIM_IMAGE_LOADER), NULL, (void **) &shim_image_loader) == EFI_SUCCESS; } static bool shim_validate( const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) { EFI_STATUS err; _cleanup_free_ char *file_buffer_owned = NULL; if (!file_buffer) { if (!device_path) return false; EFI_HANDLE device_handle; EFI_DEVICE_PATH *file_dp = (EFI_DEVICE_PATH *) device_path; err = BS->LocateDevicePath( MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), &file_dp, &device_handle); if (err != EFI_SUCCESS) return false; _cleanup_file_close_ EFI_FILE *root = NULL; err = open_volume(device_handle, &root); if (err != EFI_SUCCESS) return false; _cleanup_free_ char16_t *dp_str = NULL; err = device_path_to_str(file_dp, &dp_str); if (err != EFI_SUCCESS) return false; err = file_read(root, dp_str, 0, 0, &file_buffer_owned, &file_size); if (err != EFI_SUCCESS) return false; file_buffer = file_buffer_owned; } struct ShimLock *shim_lock; err = BS->LocateProtocol(MAKE_GUID_PTR(SHIM_LOCK), NULL, (void **) &shim_lock); if (err != EFI_SUCCESS) return false; return shim_lock->shim_verify(file_buffer, file_size) == EFI_SUCCESS; } EFI_STATUS shim_load_image( EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, bool boot_policy, EFI_HANDLE *ret_image) { assert(device_path); assert(ret_image); // TODO: drop lock protocol and just use plain BS->LoadImage once Shim < 16 is no longer supported bool have_shim = shim_loaded() && !shim_loader_available(); if (have_shim) install_security_override(shim_validate, NULL); EFI_STATUS ret = BS->LoadImage( /* BootPolicy= */ boot_policy, parent, (EFI_DEVICE_PATH *) device_path, /* SourceBuffer= */ NULL, /* SourceSize= */ 0, ret_image); if (have_shim) uninstall_security_override(); return ret; } void shim_retain_protocol(void) { uint8_t value = 1; // TODO: drop setting this var once Shim < 16 is no longer supported, as the lock protocol is no longer needed if (shim_loader_available() || !shim_loaded()) return; /* Ask Shim to avoid uninstalling its security protocol, so that we can use it from sd-stub to * validate PE addons. By default, Shim uninstalls its protocol when calling StartImage(). * Requires Shim 15.8. */ (void) efivar_set_raw(MAKE_GUID_PTR(SHIM_LOCK), u"ShimRetainProtocol", &value, sizeof(value), 0); } ubustub-1/smbios.c000066400000000000000000000220751504315023600143520ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "efi-string.h" #include "smbios.h" #include "util.h" #define SMBIOS_TABLE_GUID \ GUID_DEF(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) #define SMBIOS3_TABLE_GUID \ GUID_DEF(0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) typedef struct { uint8_t anchor_string[4]; uint8_t entry_point_structure_checksum; uint8_t entry_point_length; uint8_t major_version; uint8_t minor_version; uint16_t max_structure_size; uint8_t entry_point_revision; uint8_t formatted_area[5]; uint8_t intermediate_anchor_string[5]; uint8_t intermediate_checksum; uint16_t table_length; uint32_t table_address; uint16_t number_of_smbios_structures; uint8_t smbios_bcd_revision; } _packed_ SmbiosEntryPoint; typedef struct { uint8_t anchor_string[5]; uint8_t entry_point_structure_checksum; uint8_t entry_point_length; uint8_t major_version; uint8_t minor_version; uint8_t docrev; uint8_t entry_point_revision; uint8_t reserved; uint32_t table_maximum_size; uint64_t table_address; } _packed_ Smbios3EntryPoint; typedef struct { uint8_t type; uint8_t length; uint8_t handle[2]; } _packed_ SmbiosHeader; typedef struct { SmbiosHeader header; uint8_t vendor; uint8_t bios_version; uint16_t bios_segment; uint8_t bios_release_date; uint8_t bios_size; uint64_t bios_characteristics; uint8_t bios_characteristics_ext[2]; } _packed_ SmbiosTableType0; typedef struct { SmbiosHeader header; uint8_t manufacturer; uint8_t product_name; uint8_t version; uint8_t serial_number; EFI_GUID uuid; uint8_t wake_up_type; uint8_t sku_number; uint8_t family; } _packed_ SmbiosTableType1; typedef struct { SmbiosHeader header; uint8_t manufacturer; uint8_t product_name; uint8_t version; uint8_t serial_number; } _packed_ SmbiosTableType2; typedef struct { SmbiosHeader header; uint8_t count; char contents[]; } _packed_ SmbiosTableType11; static const void* find_smbios_configuration_table(uint64_t *ret_size) { assert(ret_size); const Smbios3EntryPoint *entry3 = find_configuration_table(MAKE_GUID_PTR(SMBIOS3_TABLE)); if (entry3 && memcmp(entry3->anchor_string, "_SM3_", 5) == 0 && entry3->entry_point_length <= sizeof(*entry3)) { *ret_size = entry3->table_maximum_size; return PHYSICAL_ADDRESS_TO_POINTER(entry3->table_address); } const SmbiosEntryPoint *entry = find_configuration_table(MAKE_GUID_PTR(SMBIOS_TABLE)); if (entry && memcmp(entry->anchor_string, "_SM_", 4) == 0 && entry->entry_point_length <= sizeof(*entry)) { *ret_size = entry->table_length; return PHYSICAL_ADDRESS_TO_POINTER(entry->table_address); } *ret_size = 0; return NULL; } static const SmbiosHeader* get_smbios_table(uint8_t type, size_t min_size, uint64_t *ret_size_left) { uint64_t size; const uint8_t *p = find_smbios_configuration_table(&size); if (!p) goto not_found; for (;;) { if (size < sizeof(SmbiosHeader)) goto not_found; const SmbiosHeader *header = (const SmbiosHeader *) p; /* End of table. */ if (header->type == 127) goto not_found; if (size < header->length) goto not_found; if (header->type == type) { /* Table is smaller than the minimum expected size? Refuse */ if (header->length < min_size) goto not_found; if (ret_size_left) *ret_size_left = size; return header; /* Yay! */ } /* Skip over formatted area. */ size -= header->length; p += header->length; /* Special case: if there are no strings appended, we'll see two NUL bytes, skip over them */ if (size >= 2 && p[0] == 0 && p[1] == 0) { size -= 2; p += 2; continue; } /* Skip over a populated string table. */ bool first = true; for (;;) { const uint8_t *e = memchr(p, 0, size); if (!e) goto not_found; if (!first && e == p) {/* Double NUL byte means we've reached the end of the string table. */ p++; size--; break; } size -= e + 1 - p; p = e + 1; first = false; } } not_found: if (ret_size_left) *ret_size_left = 0; return NULL; } bool smbios_in_hypervisor(void) { /* Look up BIOS Information (Type 0). */ const SmbiosTableType0 *type0 = (const SmbiosTableType0 *) get_smbios_table(0, sizeof(SmbiosTableType0), /* ret_size_left= */ NULL); if (!type0) return false; /* Bit 4 of 2nd BIOS characteristics extension bytes indicates virtualization. */ return FLAGS_SET(type0->bios_characteristics_ext[1], 1 << 4); } const char* smbios_find_oem_string(const char *name, const char *after) { uint64_t left; assert(name); const SmbiosTableType11 *type11 = (const SmbiosTableType11 *) get_smbios_table(11, sizeof(SmbiosTableType11), &left); if (!type11) return NULL; assert(left >= type11->header.length); /* get_smbios_table() already validated this */ left -= type11->header.length; for (const char *p = type11->contents, *limit = type11->contents + left; p < limit; ) { const char *e = memchr(p, 0, limit - p); if (!e || e == p) /* Double NUL byte means we've reached the end of the OEM strings. */ break; const char *suffix = startswith8(p, name); if (suffix && (!after || suffix > after)) return suffix; p = e + 1; } return NULL; } static const char* smbios_get_string(const SmbiosHeader *header, size_t nr, uint64_t left) { const char *s = (const char *) ASSERT_PTR(header); /* We assume that get_smbios_table() already validated the header size making some superficial sense */ assert(left >= header->length); s += header->length; left -= header->length; size_t index = 1; for (const char *p = s, *limit = s + left; index <= nr && p < limit; index++) { const char *e = memchr(p, 0, limit - p); if (!e || e == p) /* Double NUL byte means we've reached the end of the strings. */ break; if (index == nr) return p; p = e + 1; } return NULL; } void smbios_raw_info_populate(RawSmbiosInfo *ret_info) { uint64_t left; assert(ret_info); const SmbiosTableType1 *type1 = (const SmbiosTableType1 *) get_smbios_table(1, sizeof(SmbiosTableType1), &left); if (type1) { ret_info->manufacturer = smbios_get_string(&type1->header, type1->manufacturer, left); ret_info->product_name = smbios_get_string(&type1->header, type1->product_name, left); ret_info->product_sku = smbios_get_string(&type1->header, type1->sku_number, left); ret_info->family = smbios_get_string(&type1->header, type1->family, left); } else { ret_info->manufacturer = NULL; ret_info->product_name = NULL; ret_info->product_sku = NULL; ret_info->family = NULL; } const SmbiosTableType2 *type2 = (const SmbiosTableType2 *) get_smbios_table(2, sizeof(SmbiosTableType2), &left); if (type2) { ret_info->baseboard_manufacturer = smbios_get_string(&type2->header, type2->manufacturer, left); ret_info->baseboard_product = smbios_get_string(&type2->header, type2->product_name, left); } else { ret_info->baseboard_manufacturer = NULL; ret_info->baseboard_product = NULL; } } void smbios_raw_info_get_cached(RawSmbiosInfo *ret_info) { static RawSmbiosInfo info = {}; static bool cached = false; assert(ret_info); if (!cached) { smbios_raw_info_populate(&info); cached = true; } *ret_info = info; } ubustub-1/string-util-fundamental.c000066400000000000000000000171561504315023600176370ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "macro-fundamental.h" #include "string-util-fundamental.h" sd_char *startswith(const sd_char *s, const sd_char *prefix) { size_t l; assert(s); assert(prefix); l = strlen(prefix); if (!strneq(s, prefix, l)) return NULL; return (sd_char*) s + l; } sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) { size_t l; assert(s); assert(prefix); l = strlen(prefix); if (!strncaseeq(s, prefix, l)) return NULL; return (sd_char*) s + l; } sd_char* endswith(const sd_char *s, const sd_char *suffix) { size_t sl, pl; assert(s); assert(suffix); sl = strlen(s); pl = strlen(suffix); if (pl == 0) return (sd_char*) s + sl; if (sl < pl) return NULL; if (!streq(s + sl - pl, suffix)) return NULL; return (sd_char*) s + sl - pl; } sd_char* endswith_no_case(const sd_char *s, const sd_char *suffix) { size_t sl, pl; assert(s); assert(suffix); sl = strlen(s); pl = strlen(suffix); if (pl == 0) return (sd_char*) s + sl; if (sl < pl) return NULL; if (!strcaseeq(s + sl - pl, suffix)) return NULL; return (sd_char*) s + sl - pl; } static bool is_valid_version_char(sd_char a) { return ascii_isdigit(a) || ascii_isalpha(a) || IN_SET(a, '~', '-', '^', '.'); } int strverscmp_improved(const sd_char *a, const sd_char *b) { /* This function is similar to strverscmp(3), but it treats '-' and '.' as separators. * * The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distinguishes e.g. * '123a' and '123.a', with '123a' being newer. * * It allows direct comparison of strings which contain both a version and a release; e.g. * '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'. * * The input string is split into segments. Each segment is numeric or alphabetic, and may be * prefixed with the following: * '~' : used for pre-releases, a segment prefixed with this is the oldest, * '-' : used for the separator between version and release, * '^' : used for patched releases, a segment with this is newer than one with '-'. * '.' : used for point releases. * Note that no prefix segment is the newest. All non-supported characters are dropped, and * handled as a separator of segments, e.g., '123_a' is equivalent to '123a'. * * By using this, version strings can be sorted like following: * (older) 122.1 * ^ 123~rc1-1 * | 123 * | 123-a * | 123-a.1 * | 123-1 * | 123-1.1 * | 123^post1 * | 123.a-1 * | 123.1-1 * v 123a-1 * (newer) 124-1 */ a = strempty(a); b = strempty(b); for (;;) { const sd_char *aa, *bb; int r; /* Drop leading invalid characters. */ while (*a != '\0' && !is_valid_version_char(*a)) a++; while (*b != '\0' && !is_valid_version_char(*b)) b++; /* Handle '~'. Used for pre-releases, e.g. 123~rc1, or 4.5~alpha1 */ if (*a == '~' || *b == '~') { /* The string prefixed with '~' is older. */ r = CMP(*a != '~', *b != '~'); if (r != 0) return r; /* Now both strings are prefixed with '~'. Compare remaining strings. */ a++; b++; } /* If at least one string reaches the end, then longer is newer. * Note that except for '~' prefixed segments, a string which has more segments is newer. * So, this check must be after the '~' check. */ if (*a == '\0' || *b == '\0') return CMP(*a, *b); /* Handle '-', which separates version and release, e.g 123.4-3.1.fc33.x86_64 */ if (*a == '-' || *b == '-') { /* The string prefixed with '-' is older (e.g., 123-9 vs 123.1-1) */ r = CMP(*a != '-', *b != '-'); if (r != 0) return r; a++; b++; } /* Handle '^'. Used for patched release. */ if (*a == '^' || *b == '^') { r = CMP(*a != '^', *b != '^'); if (r != 0) return r; a++; b++; } /* Handle '.'. Used for point releases. */ if (*a == '.' || *b == '.') { r = CMP(*a != '.', *b != '.'); if (r != 0) return r; a++; b++; } if (ascii_isdigit(*a) || ascii_isdigit(*b)) { /* Find the leading numeric segments. One may be an empty string. So, * numeric segments are always newer than alpha segments. */ for (aa = a; ascii_isdigit(*aa); aa++) ; for (bb = b; ascii_isdigit(*bb); bb++) ; /* Check if one of the strings was empty, but the other not. */ r = CMP(a != aa, b != bb); if (r != 0) return r; /* Skip leading '0', to make 00123 equivalent to 123. */ while (*a == '0') a++; while (*b == '0') b++; /* To compare numeric segments without parsing their values, first compare the * lengths of the segments. Eg. 12345 vs 123, longer is newer. */ r = CMP(aa - a, bb - b); if (r != 0) return r; /* Then, compare them as strings. */ r = CMP(strncmp(a, b, aa - a), 0); if (r != 0) return r; } else { /* Find the leading non-numeric segments. */ for (aa = a; ascii_isalpha(*aa); aa++) ; for (bb = b; ascii_isalpha(*bb); bb++) ; /* Note that the segments are usually not NUL-terminated. */ r = CMP(strncmp(a, b, MIN(aa - a, bb - b)), 0); if (r != 0) return r; /* Longer is newer, e.g. abc vs abcde. */ r = CMP(aa - a, bb - b); if (r != 0) return r; } /* The current segments are equivalent. Let's move to the next one. */ a = aa; b = bb; } } ubustub-1/stub.c000066400000000000000000000362551504315023600140400ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-path-util.h" #include "devicetree.h" #include "efi-efivars.h" #include "efi-log.h" #include "export-vars.h" #include "iovec-util-fundamental.h" #include "linux.h" #include "measure.h" #include "memory-util-fundamental.h" #include "part-discovery.h" #include "pe.h" #include "proto/shell-parameters.h" #include "random-seed.h" #include "sbat.h" #include "secure-boot.h" #include "shim.h" #include "smbios.h" #include "tpm2-pcr.h" #include "uki.h" #include "url-discovery.h" #include "util.h" #include "version.h" /* magic string to find in the binary image */ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: ubustub " GIT_VERSION " ####"); DECLARE_SBAT(SBAT_STUB_SECTION_TEXT); static char16_t* pe_section_to_str16( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, const PeSectionVector *section) { assert(loaded_image); assert(section); if (!PE_SECTION_VECTOR_IS_SET(section)) return NULL; return xstrn8_to_16((const char *) loaded_image->ImageBase + section->memory_offset, section->memory_size); } static char *pe_section_to_str8( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, const PeSectionVector *section) { assert(loaded_image); assert(section); if (!PE_SECTION_VECTOR_IS_SET(section)) return NULL; return xstrndup8((const char *)loaded_image->ImageBase + section->memory_offset, section->memory_size); } static void combine_measured_flag(int *value, int measured) { assert(value); /* Combine the "measured" flag in a sensible way: if we haven't measured anything yet, the first * write is taken as is. Later writes can only turn off the flag, never on again. Or in other words, * we eventually want to return true iff we really measured *everything* there was to measure. * * Reminder how the "measured" flag actually works: * > 0 → something was measured * == 0 → there was something to measure but we didn't (because no TPM or so) * < 0 → nothing has been submitted for measurement so far */ if (measured < 0) return; *value = *value < 0 ? measured : *value && measured; } static void export_stub_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) { static const uint64_t stub_features = EFI_STUB_FEATURE_REPORT_BOOT_PARTITION | /* We set LoaderDevicePartUUID */ EFI_STUB_FEATURE_THREE_PCRS | /* We can measure kernel image, parameters and sysext */ EFI_STUB_FEATURE_RANDOM_SEED | /* We pass a random seed to the kernel */ EFI_STUB_FEATURE_REPORT_STUB_PARTITION | /* We set StubDevicePartUUID + StubImageIdentifier */ EFI_STUB_FEATURE_REPORT_URL | /* We set StubDeviceURL + LoaderDeviceURL */ 0; assert(loaded_image); /* add StubInfo (this is one is owned by the stub, hence we unconditionally override this with our * own data) */ (void) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubInfo", u"ubustub " GIT_VERSION, 0); (void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"StubFeatures", stub_features, 0); if (loaded_image->DeviceHandle) { _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle); if (uuid) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubDevicePartUUID", uuid, 0); _cleanup_free_ char16_t *url = disk_get_url(loaded_image->DeviceHandle); if (url) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubDeviceURL", url, 0); } if (loaded_image->FilePath) { _cleanup_free_ char16_t *s = NULL; if (device_path_to_str(loaded_image->FilePath, &s) == EFI_SUCCESS) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"StubImageIdentifier", s, 0); } } static void parse_cmdline(char16_t *p) { assert(p); while (*p != '\0') { const char16_t *debug = L"debug"; size_t debug_len = strlen16(debug); if (strncmp16(p, debug, debug_len) == 0 && (p[debug_len] == ' ' || p[debug_len] == '\0')) log_isdebug = true; p = strchr16(p, ' '); if (p == NULL) return; p++; } } static void process_arguments( EFI_HANDLE stub_image, EFI_LOADED_IMAGE_PROTOCOL *loaded_image, char16_t **ret_cmdline) { assert(stub_image); assert(loaded_image); assert(ret_cmdline); /* The UEFI shell registers EFI_SHELL_PARAMETERS_PROTOCOL onto images it runs. This lets us know that * LoadOptions starts with the stub binary path which we want to strip off. */ EFI_SHELL_PARAMETERS_PROTOCOL *shell; if (BS->HandleProtocol(stub_image, MAKE_GUID_PTR(EFI_SHELL_PARAMETERS_PROTOCOL), (void **) &shell) != EFI_SUCCESS) { /* We also do a superficial check whether first character of passed command line * is printable character (for compat with some Dell systems which fill in garbage?). */ if (loaded_image->LoadOptionsSize < sizeof(char16_t) || ((const char16_t *) loaded_image->LoadOptions)[0] <= 0x1F) goto nothing; /* Not running from EFI shell, use entire LoadOptions. Note that LoadOptions is a void*, so * it could actually be anything! */ char16_t *c = xstrndup16(loaded_image->LoadOptions, loaded_image->LoadOptionsSize / sizeof(char16_t)); *ret_cmdline = mangle_stub_cmdline(c); return; } if (shell->Argc <= 1) /* No arguments were provided? Then we fall back to built-in cmdline. */ goto nothing; size_t i = 1; if (i < shell->Argc) { /* Assemble the command line ourselves without our stub path. */ *ret_cmdline = xstrdup16(shell->Argv[i++]); for (; i < shell->Argc; i++) { _cleanup_free_ char16_t *old = *ret_cmdline; *ret_cmdline = xasprintf("%ls %ls", old, shell->Argv[i]); } } else *ret_cmdline = NULL; return; nothing: *ret_cmdline = NULL; return; } static inline void iovec_array_extend(struct iovec **arr, size_t *n_arr, struct iovec elem) { assert(arr); assert(n_arr); if (!iovec_is_set(&elem)) return; *arr = xrealloc(*arr, *n_arr * sizeof(struct iovec), (*n_arr + 1) * sizeof(struct iovec)); (*arr)[(*n_arr)++] = elem; } static void refresh_random_seed(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) { EFI_STATUS err; assert(loaded_image); /* Handle case, where bootloader doesn't support DeviceHandle. */ if (!loaded_image->DeviceHandle) return; /* Don't measure again, if sd-boot already initialized the random seed */ uint64_t loader_features = 0; (void) efivar_get_uint64_le(MAKE_GUID_PTR(LOADER), u"LoaderFeatures", &loader_features); if (FLAGS_SET(loader_features, EFI_LOADER_FEATURE_RANDOM_SEED)) return; _cleanup_file_close_ EFI_FILE *esp_dir = NULL; err = partition_open(MAKE_GUID_PTR(ESP), loaded_image->DeviceHandle, NULL, &esp_dir); if (err != EFI_SUCCESS) /* Non-fatal on failure, so that we still boot without it. */ return; (void) process_random_seed(esp_dir); } static void measure_sections( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, const PeSectionVector sections[static _UNIFIED_SECTION_MAX], int *sections_measured) { assert(loaded_image); assert(sections); assert(sections_measured); /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written * into so far), so that we have one PCR that we can nicely write policies against because it * contains all static data of this image, and thus can be easily be pre-calculated. */ for (UnifiedSection section = 0; section < _UNIFIED_SECTION_MAX; section++) { if (!unified_section_measure(section)) /* shall not measure? */ continue; if (!PE_SECTION_VECTOR_IS_SET(sections + section)) /* not found */ continue; /* First measure the name of the section */ bool m = false; (void) tpm_log_ipl_event_ascii( TPM2_PCR_KERNEL_BOOT, POINTER_TO_PHYSICAL_ADDRESS(unified_sections[section]), strsize8(unified_sections[section]), /* including NUL byte */ unified_sections[section], &m); combine_measured_flag(sections_measured, m); /* Then measure the data of the section */ m = false; (void) tpm_log_ipl_event_ascii( TPM2_PCR_KERNEL_BOOT, POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + sections[section].memory_offset, sections[section].memory_size, unified_sections[section], &m); combine_measured_flag(sections_measured, m); } } static void export_pcr_variables( int sections_measured, int parameters_measured, int sysext_measured, int confext_measured) { /* After we are done with measuring, set an EFI variable that tells userspace this was done * successfully, and encode in it which PCR was used. */ if (sections_measured > 0) (void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrKernelImage", TPM2_PCR_KERNEL_BOOT, 0); if (parameters_measured > 0) (void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0); if (sysext_measured > 0) (void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS, 0); if (confext_measured > 0) (void) efivar_set_uint64_str16(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDConfExts", TPM2_PCR_KERNEL_CONFIG, 0); } static void install_embedded_devicetree( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, const PeSectionVector sections[static _UNIFIED_SECTION_MAX], struct devicetree_state *dt_state) { EFI_STATUS err; assert(loaded_image); assert(sections); assert(dt_state); UnifiedSection section = _UNIFIED_SECTION_MAX; /* Use automatically selected DT if available, otherwise go for "normal" one */ if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTBAUTO)) section = UNIFIED_SECTION_DTBAUTO; else if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB)) section = UNIFIED_SECTION_DTB; else return; err = devicetree_install_from_memory( dt_state, (const uint8_t*) loaded_image->ImageBase + sections[section].memory_offset, sections[section].memory_size); if (err != EFI_SUCCESS) log_error_status(err, "Error loading embedded devicetree, ignoring: %m"); } static EFI_STATUS find_sections( EFI_LOADED_IMAGE_PROTOCOL *loaded_image, PeSectionVector sections[static _UNIFIED_SECTION_MAX]) { EFI_STATUS err; assert(loaded_image); assert(sections); const PeSectionHeader *section_table; size_t n_section_table; err = pe_section_table_from_base(loaded_image->ImageBase, §ion_table, &n_section_table); if (err != EFI_SUCCESS) return log_error_status(err, "Unable to locate PE section table: %m"); /* Get the base sections */ pe_locate_sections( section_table, n_section_table, unified_sections, /* validate_base= */ PTR_TO_SIZE(loaded_image->ImageBase), sections); if (!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_LINUX)) return log_error_status(EFI_NOT_FOUND, "Image lacks .linux section."); return EFI_SUCCESS; } static EFI_STATUS run(EFI_HANDLE image) { int sections_measured = -1, parameters_measured = -1, sysext_measured = -1, confext_measured = -1; _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {}; _cleanup_free_ char16_t *cmdline = NULL; struct iovec initrd = {}; PeSectionVector sections[ELEMENTSOF(unified_sections)] = {}; EFI_LOADED_IMAGE_PROTOCOL *loaded_image; _cleanup_free_ char *uname = NULL; EFI_STATUS err; err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image); if (err != EFI_SUCCESS) return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m"); /* Pick up the arguments passed to us, and return the rest * as potential command line to use. */ (void) process_arguments(image, loaded_image, &cmdline); parse_cmdline(cmdline); /* Find the sections we want to operate on */ err = find_sections(loaded_image, sections); if (err != EFI_SUCCESS) return err; measure_sections(loaded_image, sections, §ions_measured); refresh_random_seed(loaded_image); uname = pe_section_to_str8(loaded_image, sections + UNIFIED_SECTION_UNAME); export_common_variables(loaded_image); export_stub_variables(loaded_image); /* Load the base device tree. */ install_embedded_devicetree(loaded_image, sections, &dt_state); /* Find initrd if there is a .initrd section */ if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_INITRD)) initrd = IOVEC_MAKE( (const uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_INITRD].memory_offset, sections[UNIFIED_SECTION_INITRD].memory_size); /* Export variables indicating what we measured */ export_pcr_variables(sections_measured, parameters_measured, sysext_measured, confext_measured); struct iovec kernel = IOVEC_MAKE( (const uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_LINUX].memory_offset, sections[UNIFIED_SECTION_LINUX].memory_size); err = linux_exec(image, cmdline, &kernel, &initrd); return err; } DEFINE_EFI_MAIN_FUNCTION(run, "ubustub", /* wait_for_debugger= */ false); ubustub-1/uki.c000066400000000000000000000023631504315023600136440ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include "uki.h" const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = { /* These section names must fit in 8ch (excluding any trailing NUL) as per PE spec for executables: * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers * (Note that PE *object* files may have longer section names (via indirection in the string table) but * this is not allowed for PE *executables*, which UKIs are.) */ [UNIFIED_SECTION_LINUX] = ".linux", [UNIFIED_SECTION_OSREL] = ".osrel", [UNIFIED_SECTION_CMDLINE] = ".cmdline", [UNIFIED_SECTION_INITRD] = ".initrd", [UNIFIED_SECTION_UCODE] = ".ucode", [UNIFIED_SECTION_SPLASH] = ".splash", [UNIFIED_SECTION_DTB] = ".dtb", [UNIFIED_SECTION_UNAME] = ".uname", [UNIFIED_SECTION_SBAT] = ".sbat", [UNIFIED_SECTION_PCRSIG] = ".pcrsig", [UNIFIED_SECTION_PCRPKEY] = ".pcrpkey", [UNIFIED_SECTION_PROFILE] = ".profile", [UNIFIED_SECTION_DTBAUTO] = ".dtbauto", [UNIFIED_SECTION_HWIDS] = ".hwids", [UNIFIED_SECTION_EFIFW] = ".efifw", NULL, }; ubustub-1/url-discovery.c000066400000000000000000000015661504315023600156670ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-path-util.h" #include "efi-string.h" #include "proto/device-path.h" #include "url-discovery.h" char16_t *disk_get_url(EFI_HANDLE *handle) { EFI_STATUS err; EFI_DEVICE_PATH *dp; /* export the device path this image is started from */ if (!handle) return NULL; err = BS->HandleProtocol(handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp); if (err != EFI_SUCCESS) return NULL; for (; !device_path_is_end(dp); dp = device_path_next_node(dp)) { if (dp->Type != MESSAGING_DEVICE_PATH || dp->SubType != MSG_URI_DP) continue; URI_DEVICE_PATH *udp = (URI_DEVICE_PATH*) dp; return xstrn8_to_16(udp->Uri, dp->Length); } return NULL; } ubustub-1/util.c000066400000000000000000000401561504315023600140330ustar00rootroot00000000000000/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-path-util.h" #include "efi-log.h" #include "efi-string.h" #include "memory-util-fundamental.h" #include "proto/device-path.h" #include "proto/simple-text-io.h" #include "string-util-fundamental.h" #include "util.h" #include "version.h" /* Never try to read more than 16G into memory (and on 32bit 1G) */ #define FILE_READ_MAX MIN(SIZE_MAX/4, UINT64_C(16)*1024U*1024U*1024U) void free(void *p) { if (!p) return; /* Debugging an invalid free requires trace logging to find the call site or a debugger attached. For * release builds it is not worth the bother to even warn when we cannot even print a call stack. */ #ifdef EFI_DEBUG assert_se(BS->FreePool(p) == EFI_SUCCESS); #else (void) BS->FreePool(p); #endif } void convert_efi_path(char16_t *path) { assert(path); for (size_t i = 0, fixed = 0;; i++) { /* Fix device path node separator. */ path[fixed] = (path[i] == '/') ? '\\' : path[i]; /* Double '\' is not allowed in EFI file paths. */ if (fixed > 0 && path[fixed - 1] == '\\' && path[fixed] == '\\') continue; if (path[i] == '\0') break; fixed++; } } char16_t *xstr8_to_path(const char *str8) { assert(str8); char16_t *path = xstr8_to_16(str8); convert_efi_path(path); return path; } static bool shall_be_whitespace(char16_t c) { return c <= 0x20U || c == 0x7FU; /* All control characters + space */ } char16_t* mangle_stub_cmdline(char16_t *cmdline) { if (!cmdline) return cmdline; /* Skip initial whitespace */ const char16_t *p = cmdline; while (*p != 0 && shall_be_whitespace(*p)) p++; /* Turn inner control characters into proper spaces */ char16_t *e = cmdline; for (char16_t *q = cmdline; *p != 0; p++) { if (shall_be_whitespace(*p)) { *(q++) = ' '; continue; } *(q++) = *p; e = q; /* remember last non-whitespace char */ } /* Chop off trailing whitespace */ *e = 0; return cmdline; } EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf) { EFI_STATUS err; assert(file); assert(size); assert(buf); /* This is a drop-in replacement for EFI_FILE->Read() with the same API behavior. * Some broken firmwares cannot handle large file reads and will instead return * an error. As a workaround, read such files in small chunks. * Note that we cannot just try reading the whole file first on such firmware as * that will permanently break the handle even if it is reopened. * * https://github.com/systemd/systemd/issues/25911 */ if (*size == 0) return EFI_SUCCESS; size_t read = 0, remaining = *size; while (remaining > 0) { size_t chunk = MIN(1024U * 1024U, remaining); err = file->Read(file, &chunk, (uint8_t *) buf + read); if (err != EFI_SUCCESS) return err; if (chunk == 0) /* Caller requested more bytes than are in file. */ break; assert(chunk <= remaining); read += chunk; remaining -= chunk; } *size = read; return EFI_SUCCESS; } EFI_STATUS file_handle_read( EFI_FILE *handle, uint64_t offset, size_t size, char **ret, size_t *ret_size) { _cleanup_free_ char *buf = NULL; EFI_STATUS err; assert(handle); assert(ret); if (size == 0) { _cleanup_free_ EFI_FILE_INFO *info = NULL; err = get_file_info(handle, &info, NULL); if (err != EFI_SUCCESS) return err; if (info->FileSize > SIZE_MAX) /* overflow check */ return EFI_BAD_BUFFER_SIZE; size = info->FileSize; } if (size > FILE_READ_MAX) /* make sure we don't read unbounded data into RAM */ return EFI_BAD_BUFFER_SIZE; if (offset > 0) { err = handle->SetPosition(handle, offset); if (err != EFI_SUCCESS) return err; } /* Allocate some extra bytes to guarantee the result is NUL-terminated for char and char16_t strings. */ size_t extra = size % sizeof(char16_t) + sizeof(char16_t); buf = xmalloc(size + extra); err = chunked_read(handle, &size, buf); if (err != EFI_SUCCESS) return err; /* Note that chunked_read() changes size to reflect the actual bytes read. */ memzero(buf + size, extra); *ret = TAKE_PTR(buf); if (ret_size) *ret_size = size; return err; } EFI_STATUS file_read( EFI_FILE *dir, const char16_t *name, uint64_t offset, size_t size, char **ret, size_t *ret_size) { EFI_STATUS err; assert(dir); assert(name); assert(ret); _cleanup_file_close_ EFI_FILE *handle = NULL; err = dir->Open(dir, &handle, (char16_t*) name, EFI_FILE_MODE_READ, 0ULL); if (err != EFI_SUCCESS) return err; return file_handle_read(handle, offset, size, ret, ret_size); } void print_at(size_t x, size_t y, size_t attr, const char16_t *str) { assert(str); ST->ConOut->SetCursorPosition(ST->ConOut, x, y); ST->ConOut->SetAttribute(ST->ConOut, attr); ST->ConOut->OutputString(ST->ConOut, (char16_t *) str); } void clear_screen(size_t attr) { log_wait(); ST->ConOut->SetAttribute(ST->ConOut, attr); ST->ConOut->ClearScreen(ST->ConOut); } void sort_pointer_array( void **array, size_t n_members, compare_pointer_func_t compare) { assert(array || n_members == 0); assert(compare); if (n_members <= 1) return; for (size_t i = 1; i < n_members; i++) { size_t k; void *entry = array[i]; for (k = i; k > 0; k--) { if (compare(array[k - 1], entry) <= 0) break; array[k] = array[k - 1]; } array[k] = entry; } } EFI_STATUS get_file_info(EFI_FILE *handle, EFI_FILE_INFO **ret, size_t *ret_size) { size_t size = EFI_FILE_INFO_MIN_SIZE; _cleanup_free_ EFI_FILE_INFO *fi = NULL; EFI_STATUS err; assert(handle); assert(ret); fi = xmalloc(size); err = handle->GetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), &size, fi); if (err == EFI_BUFFER_TOO_SMALL) { free(fi); fi = xmalloc(size); /* GetInfo tells us the required size, let's use that now */ err = handle->GetInfo(handle, MAKE_GUID_PTR(EFI_FILE_INFO), &size, fi); } if (err != EFI_SUCCESS) return err; *ret = TAKE_PTR(fi); if (ret_size) *ret_size = size; return EFI_SUCCESS; } EFI_STATUS readdir( EFI_FILE *handle, EFI_FILE_INFO **buffer, size_t *buffer_size) { EFI_STATUS err; size_t sz; assert(handle); assert(buffer); assert(buffer_size); /* buffer/buffer_size are both in and output parameters. Should be zero-initialized initially, and * the specified buffer needs to be freed by caller, after final use. */ if (!*buffer) { sz = EFI_FILE_INFO_MIN_SIZE; *buffer = xmalloc(sz); *buffer_size = sz; } else sz = *buffer_size; err = handle->Read(handle, &sz, *buffer); if (err == EFI_BUFFER_TOO_SMALL) { free(*buffer); *buffer = xmalloc(sz); *buffer_size = sz; err = handle->Read(handle, &sz, *buffer); } if (err != EFI_SUCCESS) return err; if (sz == 0) { /* End of directory */ *buffer = mfree(*buffer); *buffer_size = 0; } return EFI_SUCCESS; } bool is_ascii(const char16_t *f) { if (!f) return false; for (; *f != 0; f++) if (*f > 127) return false; return true; } char16_t **strv_free(char16_t **v) { if (!v) return NULL; for (char16_t **i = v; *i; i++) free(*i); return mfree(v); } EFI_STATUS open_directory( EFI_FILE *root, const char16_t *path, EFI_FILE **ret) { _cleanup_file_close_ EFI_FILE *dir = NULL; _cleanup_free_ EFI_FILE_INFO *file_info = NULL; EFI_STATUS err; assert(root); /* Opens a file, and then verifies it is actually a directory */ err = root->Open(root, &dir, (char16_t *) path, EFI_FILE_MODE_READ, 0); if (err != EFI_SUCCESS) return err; err = get_file_info(dir, &file_info, NULL); if (err != EFI_SUCCESS) return err; if (!FLAGS_SET(file_info->Attribute, EFI_FILE_DIRECTORY)) return EFI_LOAD_ERROR; *ret = TAKE_PTR(dir); return EFI_SUCCESS; } __attribute__((noinline)) void notify_debugger(const char *identity, volatile bool wait) { #ifdef EFI_DEBUG printf("%s@%p %s\n", identity, __executable_start, GIT_VERSION); if (wait) printf("Waiting for debugger to attach...\n"); /* This is a poor programmer's breakpoint to wait until a debugger * has attached to us. Just "set variable wait = 0" or "return" to continue. */ while (wait) /* Prefer asm based stalling so that gdb has a source location to present. */ # if defined(__i386__) || defined(__x86_64__) asm volatile("pause"); # elif defined(__aarch64__) asm volatile("wfi"); # else BS->Stall(5000); # endif #endif } #if defined(__i386__) || defined(__x86_64__) static uint8_t inb(uint16_t port) { uint8_t value; asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port)); return value; } static void outb(uint16_t port, uint8_t value) { asm volatile("outb %0, %1" : : "a"(value), "Nd"(port)); } void beep(unsigned beep_count) { enum { PITCH = 500, BEEP_DURATION_USEC = 100 * 1000, WAIT_DURATION_USEC = 400 * 1000, PIT_FREQUENCY = 0x1234dd, SPEAKER_CONTROL_PORT = 0x61, SPEAKER_ON_MASK = 0x03, TIMER_PORT_MAGIC = 0xB6, TIMER_CONTROL_PORT = 0x43, TIMER_CONTROL2_PORT = 0x42, }; /* Set frequency. */ uint32_t counter = PIT_FREQUENCY / PITCH; outb(TIMER_CONTROL_PORT, TIMER_PORT_MAGIC); outb(TIMER_CONTROL2_PORT, counter & 0xFF); outb(TIMER_CONTROL2_PORT, (counter >> 8) & 0xFF); uint8_t value = inb(SPEAKER_CONTROL_PORT); while (beep_count > 0) { /* Turn speaker on. */ value |= SPEAKER_ON_MASK; outb(SPEAKER_CONTROL_PORT, value); BS->Stall(BEEP_DURATION_USEC); /* Turn speaker off. */ value &= ~SPEAKER_ON_MASK; outb(SPEAKER_CONTROL_PORT, value); beep_count--; if (beep_count > 0) BS->Stall(WAIT_DURATION_USEC); } } #endif EFI_STATUS open_volume(EFI_HANDLE device, EFI_FILE **ret_file) { EFI_STATUS err; EFI_FILE *file; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *volume; assert(ret_file); err = BS->HandleProtocol(device, MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), (void **) &volume); if (err != EFI_SUCCESS) return err; err = volume->OpenVolume(volume, &file); if (err != EFI_SUCCESS) return err; *ret_file = file; return EFI_SUCCESS; } void *find_configuration_table(const EFI_GUID *guid) { for (size_t i = 0; i < ST->NumberOfTableEntries; i++) if (efi_guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid)) return ST->ConfigurationTable[i].VendorTable; return NULL; } static void remove_boot_count(char16_t *path) { char16_t *prefix_end; const char16_t *tail; uint64_t ignored; assert(path); prefix_end = strchr16(path, '+'); if (!prefix_end) return; tail = prefix_end + 1; if (!parse_number16(tail, &ignored, &tail)) return; if (*tail == '-') { ++tail; if (!parse_number16(tail, &ignored, &tail)) return; } if (!IN_SET(*tail, '\0', '.')) return; strcpy16(prefix_end, tail); } char16_t *get_extra_dir(const EFI_DEVICE_PATH *file_path) { if (!file_path) return NULL; /* A device path is allowed to have more than one file path node. If that is the case they are * supposed to be concatenated. Unfortunately, the device path to text protocol simply converts the * nodes individually and then combines those with the usual '/' for device path nodes. But this does * not create a legal EFI file path that the file protocol can use. */ /* Make sure we really only got file paths. */ for (const EFI_DEVICE_PATH *node = file_path; !device_path_is_end(node); node = device_path_next_node(node)) if (node->Type != MEDIA_DEVICE_PATH || node->SubType != MEDIA_FILEPATH_DP) return NULL; _cleanup_free_ char16_t *file_path_str = NULL; if (device_path_to_str(file_path, &file_path_str) != EFI_SUCCESS) return NULL; convert_efi_path(file_path_str); remove_boot_count(file_path_str); return xasprintf("%ls.extra.d", file_path_str); } void *xmalloc(size_t size) { void *p = NULL; assert_se(BS->AllocatePool(EfiLoaderData, size, &p) == EFI_SUCCESS); return p; } bool free_and_xstrdup16(char16_t **p, const char16_t *s) { char16_t *t; assert(p); /* Replaces a string pointer with a strdup()ed new string, * possibly freeing the old one. */ if (streq_ptr(*p, s)) return false; if (s) t = xstrdup16(s); else t = NULL; free(*p); *p = t; return true; } char16_t *url_replace_last_component(const char16_t *url, const char16_t *filename) { assert(url); assert(filename); /* Find colon separating protocol and hostname */ const char16_t *d = strchr16(url, ':'); if (!d || url == d) return NULL; d++; /* Skip slashes after colon */ d += strspn(d, u"/"); /* Skip everything till next slash or end (i.e. the hostname) */ size_t n = strcspn(d, u"/?#"); if (n == 0) return NULL; d += n; const char16_t *e = d + strcspn(d, u"?#"); /* Cut off "Query" and "Fragment" */ while (e > d && e[-1] == '/') /* Eat trailing slashes */ e--; const char16_t *p = e; while (p > d && p[-1] != '/') /* Find component before that */ p--; if (e <= p) return NULL; _cleanup_free_ char16_t *chopped = xstrndup16(url, p - url); return xasprintf("%ls/%ls", chopped, filename); }