diff --git a/meta-luv/classes/luv-efi.bbclass b/meta-luv/classes/luv-efi.bbclass index 21d25a92a46..0dd21550c89 100644 --- a/meta-luv/classes/luv-efi.bbclass +++ b/meta-luv/classes/luv-efi.bbclass @@ -42,7 +42,7 @@ def extra_initrd(d): target = d.getVar('TARGET_ARCH', True) if re.search('86', target): - return '/boot/bitsrd' + return '' else: return '' @@ -85,9 +85,10 @@ efi_populate() { install -m 0644 ${DEPLOY_DIR_IMAGE}/${EFI_LOADER_IMAGE} ${DEST}${EFIDIR} fi - if echo "${TARGET_ARCH}" | grep -q "i.86" || [ "${TARGET_ARCH}" = "x86_64" ]; then - efi_populate_bits ${DEST} - fi + # TODO: only populate bits if present in features + #if echo "${TARGET_ARCH}" | grep -q "i.86" || [ "${TARGET_ARCH}" = "x86_64" ]; then + # efi_populate_bits ${DEST} + #fi # Install splash and grub.cfg files into EFI directory. install -m 0644 ${GRUBCFG} ${DEST}${EFIDIR} diff --git a/meta-luv/recipes-core/images/core-image-efi-initramfs.bb b/meta-luv/recipes-core/images/core-image-efi-initramfs.bb index 82a9cb881c1..c77c1a213f6 100644 --- a/meta-luv/recipes-core/images/core-image-efi-initramfs.bb +++ b/meta-luv/recipes-core/images/core-image-efi-initramfs.bb @@ -3,19 +3,18 @@ DESCRIPTION = "Small image capable of booting a device and running the suite of EFI tests." IMAGE_INSTALL = "\ - base-files base-passwd netbase udev systemd luv-test-manager \ - luv-test-crash luv-test-netconsole luv-test keymaps \ - kernel-image fwts bash coreutils gawk grep util-linux-agetty \ - util-linux-mount util-linux-umount kmod sed tar net-tools \ - shadow util-linux procps efivarfs-test \ - plymouth plymouth-set-default-theme kernel-efi-warnings linux-firmware kexec \ + base-files base-passwd udev systemd \ + keymaps \ + kernel-image bash coreutils grep util-linux-agetty \ + util-linux-mount util-linux-umount kmod \ + shadow util-linux procps \ + plymouth plymouth-set-default-theme \ " -X86_ADDITIONS = "chipsec python-codecs python-subprocess vmcore-dmesg bits \ - kernel-modules telemetrics" +X86_ADDITIONS = "" -IMAGE_INSTALL_append_qemux86 = "${X86_ADDITIONS}" -IMAGE_INSTALL_append_qemux86-64 = "${X86_ADDITIONS} ndctl" +IMAGE_INSTALL_append_qemux86 = "${X86_ADDITIONS} vm86-test umip-tests" +IMAGE_INSTALL_append_qemux86-64 = "${X86_ADDITIONS} umip-tests lib32-umip-tests" export IMAGE_BASENAME = "core-image-efi-initramfs" diff --git a/meta-luv/recipes-core/umip/files/COPYING b/meta-luv/recipes-core/umip/files/COPYING new file mode 100644 index 00000000000..d511905c164 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, 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 or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. However, as a +special exception, the source code 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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 to +this License. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), 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 Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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 program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; 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. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/meta-luv/recipes-core/umip/files/Makefile b/meta-luv/recipes-core/umip/files/Makefile new file mode 100644 index 00000000000..99b577be520 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/Makefile @@ -0,0 +1,92 @@ +cpuid: CFLAGS += -fno-omit-frame-pointer +cpuid: + $(CC) $(CFLAGS) -o umip_cpuid cpuid.c + +x86_64_minimal: CFLAGS += -fno-omit-frame-pointer +x86_64_minimal: + $(CC) $(CFLAGS) -c umip_utils.c -o umip_utils_64.o + + $(CC) $(CFLAGS) -o umip_test_opnds_64 umip_utils_64.o umip_test_opnds.c + $(CC) $(CFLAGS) -o umip_test_basic_64 umip_utils_64.o umip_test_basic.c + $(CC) $(CFLAGS) -o umip_exceptions_64 umip_utils_64.o umip_exceptions.c + + python umip_test_gen_64.py + $(CC) $(CFLAGS) -c test_umip_ldt_64.c + $(CC) $(CFLAGS) -c umip_ldt_64.c + $(CC) $(CFLAGS) -o umip_ldt_64 test_umip_ldt_64.o umip_ldt_64.o umip_utils_64.o + +x86_64_emul_all: CFLAGS += -DEMULATE_ALL -fno-omit-frame-pointer +x86_64_emul_all: x86_64_minimal + $(CC) $(CFLAGS) -c umip_utils.c -o umip_utils_64.o + + $(CC) $(CFLAGS) -o umip_test_opnds_64_emul_all umip_utils_64.o umip_test_opnds.c + $(CC) $(CFLAGS) -o umip_test_basic_64_emul_all umip_utils_64.o umip_test_basic.c + $(CC) $(CFLAGS) -o umip_exceptions_64_emul_all umip_utils_64.o umip_exceptions.c + + python umip_test_gen_64.py --emulate-all + $(CC) $(CFLAGS) -c test_umip_ldt_64.c + $(CC) $(CFLAGS) -c umip_ldt_64.c + $(CC) $(CFLAGS) -o umip_ldt_64_emul_all test_umip_ldt_64.o umip_ldt_64.o umip_utils_64.o + +x86_64: x86_64_minimal x86_64_emul_all cpuid + +i686_minimal: CFLAGS += -fno-omit-frame-pointer -m32 +i686_minimal: + $(CC) $(CFLAGS) -c umip_utils.c -o umip_utils_32.o + + $(CC) $(CFLAGS) -o umip_test_opnds_32 umip_utils_32.o umip_test_opnds.c + $(CC) $(CFLAGS) -o umip_test_basic_32 umip_utils_32.o umip_test_basic.c + $(CC) $(CFLAGS) -o umip_exceptions_32 umip_utils_32.o umip_exceptions.c + + python umip_test_gen_32.py + $(CC) $(CFLAGS) -c test_umip_ldt_32.c + $(CC) $(CFLAGS) -c umip_ldt_32.c + $(CC) $(CFLAGS) -o umip_ldt_32 test_umip_ldt_32.o umip_ldt_32.o umip_utils_32.o + + python umip_test_gen_16.py + $(CC) $(CFLAGS) -c test_umip_ldt_16.c + $(CC) $(CFLAGS) -c umip_ldt_16.c + $(CC) $(CFLAGS) -o umip_ldt_16 test_umip_ldt_16.o umip_ldt_16.o umip_utils_32.o + +i686_emul_all: CFLAGS += -DEMULATE_ALL -fno-omit-frame-pointer -m32 +i686_emul_all: i686_minimal + $(CC) $(CFLAGS) -c umip_utils.c -o umip_utils_32.o + + $(CC) $(CFLAGS) -o umip_test_opnds_32_emul_all umip_utils_32.o umip_test_opnds.c + $(CC) $(CFLAGS) -o umip_test_basic_32_emul_all umip_utils_32.o umip_test_basic.c + $(CC) $(CFLAGS) -o umip_exceptions_32_emul_all umip_utils_32.o umip_exceptions.c + + python umip_test_gen_32.py --emulate-all + $(CC) $(CFLAGS) -c test_umip_ldt_32.c + $(CC) $(CFLAGS) -c umip_ldt_32.c + $(CC) $(CFLAGS) -o umip_ldt_32_emul_all test_umip_ldt_32.o umip_ldt_32.o umip_utils_32.o + + python umip_test_gen_16.py --emulate-all + $(CC) $(CFLAGS) -c test_umip_ldt_16.c + $(CC) $(CFLAGS) -c umip_ldt_16.c + $(CC) $(CFLAGS) -o umip_ldt_16_emul_all test_umip_ldt_16.o umip_ldt_16.o umip_utils_32.o + +i686: i686_minimal i686_emul_all cpuid +i586: i686 + +.PHONY: clean +clean: + rm -f *.o + rm -f umip_test_basic_64 + rm -f umip_test_basic_64_emul_all + rm -f umip_test_basic_32 + rm -f umip_test_basic_32_emul_all + rm -f umip_test_opnds_64 + rm -f umip_test_opnds_64_emul_all + rm -f umip_test_opnds_32 + rm -f umip_test_opnds_32_emul_all + rm -f umip_exceptions_64 + rm -f umip_exceptions_64_emul_all + rm -f umip_exceptions_32 + rm -f umip_exceptions_32_emul_all + rm -f umip_ldt_64 + rm -f umip_ldt_64_emul_all + rm -f umip_ldt_32 + rm -f umip_ldt_32_emul_all + rm -f umip_ldt_16 + rm -f umip_ldt_16_emul_all diff --git a/meta-luv/recipes-core/umip/files/UMIP_README b/meta-luv/recipes-core/umip/files/UMIP_README new file mode 100644 index 00000000000..72fd2b21dff --- /dev/null +++ b/meta-luv/recipes-core/umip/files/UMIP_README @@ -0,0 +1,192 @@ + A QUICK GUIDE FOR UMIP TESTING + +Contents + + I. For the impatient + II. What is UMIP and how is supported in the Linux kernel? +III. Testing UMIP + a) Overview + b) Testing full emulation + c) Testing 64-bit processes + d) Testing 32-bit processes + e) Testing output format + f) The test programs + g) Things to do + + ============================================================ +I. For the impatient + +If all you have is 10 seconds, all you need to know is this: + +Assuming you have a 64-bit distro install, here is what you need to do: + + 1. If in Ubuntu: + $ sudo apt-get install ia32-libs + If in other distros, not sure; a similar package + 2. $ make x86_64 + 3. $ CFLAGS=-m32 make i586 + 4. $ umip_test_basic_64 + 5. $ umip_test_basic_32 + 6. $ umip_test_opnds_64 + 7. $ umip_test_opnds_32 + 8. $ umip_exceptions_64 + 9. $ umip_exceptions_32 + 10. $ umip_ldt_64 + 11. $ umip_ldt_32 + 12. $ umip_ldt_16 + +For each of the steps 4 through 12, look for this output + + RESULTS: passed[X], failed[0], errors[0]. + +You should have 0 failures and 0 errors. + +You are done. + + ============================================================ +II. What is UMIP and how is supported in the Linux kernel? + +User-mode Instruction Prevention, UMIP is a feature present in new Intel +processors that prevents the execution of the instructions SGDT, SIDT, SLDT, +SMSW and STR while running in CLP>0. In such a case, a general protection fault +exception is issued. + +Functionality has been put in the kernel to trap this general protection fault +exception. When this happens, the kernel provides to the caller dummy values +as the result for these instructions. However, emulation is not done in every +case. It is done only for 32-bit processes and only for the instructions SGDT, +SIDT and SMSW. For 64-bit processes no emulation is provideded. The instructions +STR and SLDT are not emulated in any case. + +However, the Linux kernel can be patched to provide emulation in all cases. + + ============================================================ +III. Testing UMIP + +a) == Overview === + +I have written several programs to test the behavior described above. Each +program can be built for 32-bit and 64-bit processes. The makefile builds both +versions and adds _32 or _64 suffixes to the executable test programs. + +b) == Achieving emulation for everything + +Also, each program can be built to test emulation for all the instructions in +both 64 and 32-bits and for all the instructions. The makefile achieves this by +adding -DEMULATE_ALL to the CFLAGS; the python scripts that generate code are +run with the option --emulate-all. Test programs built with this configuration +are added the suffix _emul_all. + +Hence, the naming convention for the test programs is: + + test_program_32/64_[emul_all] + +c) == Testing 64-bit processes + +The makefile can the test programs for all these configurations. + +To build the 64-bit test programs you can do + + $ make x86_64 + +This will build the programs umip_test_basic, umip_test_opnds, umip_exceptions, +and umip_ldt_64; see section III.a) for the relevant naming convention. + +In its default version, these programs will verify a general protection fault +is seen when executing the UMIP-protected instructions. In the _emul_all +version, programs will verify that emulation is successful and no exceptions are +generated in the process (please see the umip_exceptions special case below). + +Both the default and _emul_all versions are built with the aforementioned +command. + +d) == Testing 32-bit processes + +In a 64-bit distro, you will need to install the 32-bit compatibility libraries. +In Ubuntu, this is done with: + + $ sudo apt-get install ia32-libs + +In other distros, a similar procedure can be followed. + +Then, the 32-bit test programs can be built as: + + $ CFLAGS=-m32 make i586 + +This will build the programs umip_test_basic, umip_test_opnds, umip_exceptions, +umip_ldt_32, and umip_ldt_16; see section III.a) for the relevant naming +convention. + +In its default version, these programs will verify that emulation is successful +for the instructions SGDT, SIDT and SMSW. They will also verify that a general +proctection fault is seen for the instructions SLDT and STR. + +Both the default and _emul_all versions are built with the aforementioned +commans. + +e) == The testing output format + +Test programs use the following output format + +[info] To print information about a test case. +[pass] To inform that a test case passed. +[FAIL] To inform that a test case failed. + +RESULTS: passed[X], failed[Y], error[Z] + +Ideally, you should see all test case passed. This means that you should see +0 failures and 0 errors. + +f) The test programs + +Refer to section III.a) for the naming convention. + +* umip_est_basic. Use umip_test for a very basic test that exercises the + instructions smsw, str, sidt, sldt and sgdt from protected mode using the + global descriptortable. + +* umip_test_opnds. Use umip_test_opnds for a collection of tests that + exercises the instructions str, sldt and smsw for register and memory + operands. For registers, operand sizes are of 16 and 32 bits. Memory operands + are always 16-bits long. Addresses in these tests are computed using only the + ModRM byte. Also, these tests use the normal __USER_DS segment with a base + address of zero. + +* umip_exceptions. Use umip_exceptions that the emulation code issues the + exceptions for each of the UMIP-instructions as described in the Intel + Software Development Manual. Priority of the exceptions should be that + mentioned in the Volume 3, Section 16.9 of the aforementioned manual. That is, + for instance, if the instructions can lead to a general protection fault + exception and an illegal operand exception, verify that the latter is seen. + +* umip_ldt_64. Use umip_ldt_64 to verify all the possible 64-bit address + encodings in the UMIP-protected instructions. This includes all the ModRM, + and SiB displacement combinations. Furthermore, this test configures a Local + Descriptor Table whose segments have base addresses that are different from + the __USER_DS segment. Since this program runs in long mode, segmentation is + implemented using the FS and GS registers. The purpose of this test is to + verify that the emulation code is capable of succesfully computing linear + address out of the instruction operand and segment descriptor. + +* umip_ldt_32. Use umip_ldt_32 to verify all the possible 32-bit address + encodings in the UMIP-protected instructions. This includes all the ModRM, + and SiB displacement combinations. Furthermore, this test configures a Local + Descriptor Table whose segments have base addresses that are different from + the __USER_DS segment. The purpose of this test is to verify that the + emulation code is capable of succesfully computing linear address out of the + instruction operand and segment descriptor. + +* umip_ldt_16. Use umip_ldt_16 to verify all the possible 16-bit address + encodings in the UMIP-protected instructions. This includes all the ModRM and + displacement combinations. Furthermore, this test configure a Local Descriptor + Table with segments that have base addresses different than the __USER_DS + segment. Also, the code segment is configured for 16-bit addresses. The + purpose of this test is to verify that the emulation code is capable of + succesfully computing linear address out of the instruction operand and + segment descriptor. + +g) Things to do + +* In umip_ldt_64, test %rsp and %r12 +* Add tests for address size override prefixes +* Add test to include more than one segment override prefix diff --git a/meta-luv/recipes-core/umip/files/cpuid.c b/meta-luv/recipes-core/umip/files/cpuid.c new file mode 100644 index 00000000000..d3b466bd8fc --- /dev/null +++ b/meta-luv/recipes-core/umip/files/cpuid.c @@ -0,0 +1,57 @@ +#include +#include + +#define UMIP_MASK 0x4 + +void usage(void) +{ + printf("Usage:\n"); + printf("cpuid [eax] [ecx]\n"); + printf("Example:\n"); + printf("cpuid 0x4 0x0\n"); +} + +void print_umip(unsigned int ecx) +{ + printf("CPU has UMIP? %s\n", ecx & UMIP_MASK ? "yes" : "no"); +} + +void get_cpuid_leaf(unsigned int eax, unsigned int ecx, unsigned int *new_eax, + unsigned int *new_ecx, unsigned *new_edx) +{ + printf("Getting CPUID leaf for eax=0x%x ecx=0x%x\n", eax, ecx); + + asm volatile("mov %3, %%eax\n" + "mov %4, %%ecx\n" + "cpuid\n" + "mov %%eax, %0\n" + "mov %%ecx, %1\n" + "mov %%edx, %2\n" + : "=m"(*new_eax), "=m"(*new_ecx), "=m"(*new_edx) + : "m"(eax), "m"(ecx) + : "eax", "ecx", "edx"); +} + +int main(int argc, char **argv) +{ + unsigned int eax, ecx, edx; + unsigned int new_eax = 0xabababab, new_ecx = 0xcbcbcbcb; + unsigned int new_edx = 0xefefefef; + + if (argc != 3) { + usage(); + return 1; + } + + eax = strtoul(argv[1], NULL, 0); + ecx = strtoul(argv[2], NULL, 0); + + get_cpuid_leaf(eax, ecx, &new_eax, &new_ecx, &new_edx); + + printf("CPUID Result:\n"); + printf("eax = 0x%x\n", new_eax); + printf("ecx = 0x%x\n", new_ecx); + printf("edx = 0x%x\n", new_edx); + + print_umip(new_ecx); +} diff --git a/meta-luv/recipes-core/umip/files/umip_exceptions.c b/meta-luv/recipes-core/umip/files/umip_exceptions.c new file mode 100644 index 00000000000..f57ebe2b334 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_exceptions.c @@ -0,0 +1,423 @@ +/* + * normal_pf.c - tests UMIP emulation code when a page fault should be + * generated (i.e., the requested memory access is not mapped. No code + * is included to test cases in which Memory Protection Keys are used. + * Copyright (c) 2016 Intel Corporation + * + * GPL v2. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "umip_test_defs.h" + +extern sig_atomic_t got_signal, got_sigcode; + +int test_passed, test_failed, test_errors; + +#define gen_test_maperr_pf_inst(inst, bad_addr) \ +static void __test_maperr_pf_##inst(int exp_signum, int exp_sigcode) \ +{ \ + unsigned long *val_bad = (unsigned long *)bad_addr; \ + \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + pr_info("Test page fault because unmapped memory for %s with addr %p\n",\ + #inst, val_bad); \ + asm volatile (#inst" %0\n" NOP_SLED : "=m"(*val_bad)); \ + \ + inspect_signal(exp_signum, exp_sigcode); \ +} + +gen_test_maperr_pf_inst(smsw, 0x100000) +gen_test_maperr_pf_inst(sidt, 0x100000) +gen_test_maperr_pf_inst(sgdt, 0x100000) +gen_test_maperr_pf_inst(str, 0x100000) +gen_test_maperr_pf_inst(sldt, 0x100000) + +static void test_maperr_pf(void) +{ + int exp_signum, exp_sigcode; + int exp_signum_str_sldt, exp_sigcode_str_sldt; + + INIT_EXPECTED_SIGNAL(exp_signum, SIGSEGV, exp_sigcode, SEGV_MAPERR); + INIT_EXPECTED_SIGNAL_STR_SLDT(exp_signum_str_sldt, SIGSEGV, + exp_sigcode_str_sldt, SEGV_MAPERR); + + __test_maperr_pf_smsw(exp_signum, exp_sigcode); + __test_maperr_pf_sidt(exp_signum, exp_sigcode); + __test_maperr_pf_sgdt(exp_signum, exp_sigcode); + __test_maperr_pf_str(exp_signum_str_sldt, exp_sigcode_str_sldt); + __test_maperr_pf_sldt(exp_signum_str_sldt, exp_sigcode_str_sldt); +} + +#define gen_test_lock_prefix_inst(name, inst) \ +static void __test_lock_prefix_##name(void) \ +{ \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + pr_info("Test %s with lock prefix\n", #name); \ + /* name (%eax) with the LOCK prefix */ \ + asm volatile(inst NOP_SLED); \ + \ + inspect_signal(SIGILL, ILL_ILLOPN); \ +} + +gen_test_lock_prefix_inst(SMSW, ".byte 0xf0, 0xf, 0x1, 0x20\n") +gen_test_lock_prefix_inst(SIDT, ".byte 0xf0, 0xf, 0x1, 0x8\n") +gen_test_lock_prefix_inst(SGDT, ".byte 0xf0, 0xf, 0x1, 0x0\n") +gen_test_lock_prefix_inst(STR, ".byte 0xf0, 0xf, 0x0, 0x8\n") +gen_test_lock_prefix_inst(SLDT, ".byte 0xf0, 0xf, 0x0, 0x0\n") + +static void test_lock_prefix(void) +{ + __test_lock_prefix_SMSW(); + __test_lock_prefix_SIDT(); + __test_lock_prefix_SGDT(); + __test_lock_prefix_STR(); + __test_lock_prefix_SLDT(); +} + +#define gen_test_register_operand_inst(name, inst) \ +static void __test_register_operand_##name(void) \ +{ \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + pr_info("Test %s with register operand\n", #name); \ + /* name (%eax) with the LOCK prefix */ \ + asm volatile(inst NOP_SLED); \ + \ + inspect_signal(SIGILL, ILL_ILLOPN); \ + return; \ +} + +gen_test_register_operand_inst(SIDT, ".byte 0xf, 0x1, 0xc8\n") +gen_test_register_operand_inst(SGDT, ".byte 0xf, 0x1, 0xc0\n") + +static void test_register_operand(void) +{ + __test_register_operand_SGDT(); + __test_register_operand_SIDT(); +} + +#ifdef __x86_64__ +static void test_null_segment_selectors(void) {} +#else +#define gen_test_null_segment_selector(inst, reg) \ +static void __test_null_segment_selector_##inst##_##reg(void) \ +{ \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + pr_info("Test using null seg sel for " #inst " with " #reg "\n"); \ + asm volatile("push %" #reg "\n" \ + "push %eax\n" \ + "push %ebx\n" \ + "mov $0x1000, %eax\n" \ + "mov $0, %ebx\n" \ + "mov %bx, %" #reg "\n" \ + "smsw %" #reg ":(%eax)\n" \ + NOP_SLED \ + "pop %ebx\n" \ + "pop %eax\n" \ + "pop %" #reg "\n"); \ + \ + inspect_signal(SIGSEGV, SI_KERNEL); \ + return; \ +} + +gen_test_null_segment_selector(smsw, ds) +gen_test_null_segment_selector(smsw, es) +gen_test_null_segment_selector(smsw, fs) +gen_test_null_segment_selector(smsw, gs) +gen_test_null_segment_selector(sidt, ds) +gen_test_null_segment_selector(sidt, es) +gen_test_null_segment_selector(sidt, fs) +gen_test_null_segment_selector(sidt, gs) +gen_test_null_segment_selector(sgdt, ds) +gen_test_null_segment_selector(sgdt, es) +gen_test_null_segment_selector(sgdt, fs) +gen_test_null_segment_selector(sgdt, gs) +gen_test_null_segment_selector(str, ds) +gen_test_null_segment_selector(str, es) +gen_test_null_segment_selector(str, fs) +gen_test_null_segment_selector(str, gs) +gen_test_null_segment_selector(sldt, ds) +gen_test_null_segment_selector(sldt, es) +gen_test_null_segment_selector(sldt, fs) +gen_test_null_segment_selector(sldt, gs) + +static void test_null_segment_selectors(void) +{ + __test_null_segment_selector_smsw_ds(); + __test_null_segment_selector_smsw_es(); + __test_null_segment_selector_smsw_fs(); +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + __test_null_segment_selector_smsw_gs(); +#endif + __test_null_segment_selector_sidt_ds(); + __test_null_segment_selector_sidt_es(); + __test_null_segment_selector_sidt_fs(); +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + __test_null_segment_selector_sidt_gs(); +#endif + + __test_null_segment_selector_sgdt_ds(); + __test_null_segment_selector_sgdt_es(); + __test_null_segment_selector_sgdt_fs(); +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + __test_null_segment_selector_sgdt_gs(); +#endif + + __test_null_segment_selector_sldt_ds(); + __test_null_segment_selector_sldt_es(); + __test_null_segment_selector_sldt_fs(); + #ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + __test_null_segment_selector_sldt_gs(); +#endif + + __test_null_segment_selector_str_ds(); + __test_null_segment_selector_str_es(); + __test_null_segment_selector_str_fs(); + +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + __test_null_segment_selector_str_gs(); +#endif +} +#endif + +#ifdef __x86_64__ +static void test_addresses_outside_segment(void) {} +#else + +#define SEGMENT_SIZE 0x1000 +#define CODE_DESC_INDEX 1 +#define DATA_DESC_INDEX 2 + +#define RPL3 3 +#define TI_LDT 1 + +#define SEGMENT_SELECTOR(index) (RPL3 | (TI_LDT << 2) | (index << 3)) + +unsigned char custom_segment[SEGMENT_SIZE]; + +static int setup_data_segments() +{ + int ret; + struct user_desc desc = { + .entry_number = 0, + .base_addr = 0, + .limit = SEGMENT_SIZE, + .seg_32bit = 1, + .contents = 0, /* data */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 1 + }; + + desc.entry_number = DATA_DESC_INDEX; + desc.base_addr = (unsigned long)&custom_segment; + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install stack segment [%d].\n", ret); + return ret; + } + + return 0; +} + +#define gen_test_addresses_outside_segment(inst, sel) \ +static void __test_addresses_outside_segment_##inst##_##sel(void) \ +{ \ + int ret; \ + unsigned short seg_sel; \ + \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + \ + seg_sel = SEGMENT_SELECTOR(DATA_DESC_INDEX); \ + \ + pr_info("Test address outside of segment limit for " #inst " with " #sel"\n");\ + asm volatile("push %%" #sel"\n" \ + "push %%eax\n" \ + "push %%ebx\n" \ + "mov $0x2000, %%eax\n" \ + "mov %0, %%" #sel "\n" \ + #inst " %%" #sel ":(%%eax)\n" \ + NOP_SLED \ + "pop %%ebx\n" \ + "pop %%eax\n" \ + "pop %%" #sel "\n" \ + : \ + :"m" (seg_sel)); \ + \ + inspect_signal(SIGSEGV, SI_KERNEL); \ + return; \ +} + +gen_test_addresses_outside_segment(smsw, ds) +gen_test_addresses_outside_segment(str, ds) +gen_test_addresses_outside_segment(sldt, ds) +gen_test_addresses_outside_segment(sgdt, ds) +gen_test_addresses_outside_segment(sidt, ds) +gen_test_addresses_outside_segment(smsw, es) +gen_test_addresses_outside_segment(str, es) +gen_test_addresses_outside_segment(sldt, es) +gen_test_addresses_outside_segment(sgdt, es) +gen_test_addresses_outside_segment(sidt, es) +gen_test_addresses_outside_segment(smsw, fs) +gen_test_addresses_outside_segment(str, fs) +gen_test_addresses_outside_segment(sldt, fs) +gen_test_addresses_outside_segment(sgdt, fs) +gen_test_addresses_outside_segment(sidt, fs) +gen_test_addresses_outside_segment(smsw, gs) +gen_test_addresses_outside_segment(str, gs) +gen_test_addresses_outside_segment(sldt, gs) +gen_test_addresses_outside_segment(sgdt, gs) +gen_test_addresses_outside_segment(sidt, gs) + +static void test_addresses_outside_segment(void) +{ + int ret; + + ret = setup_data_segments(); + if (ret) + return; + + __test_addresses_outside_segment_smsw_ds(); + __test_addresses_outside_segment_str_ds(); + __test_addresses_outside_segment_sgdt_ds(); + __test_addresses_outside_segment_sidt_ds(); + __test_addresses_outside_segment_sldt_ds(); + __test_addresses_outside_segment_smsw_es(); + __test_addresses_outside_segment_str_es(); + __test_addresses_outside_segment_sgdt_es(); + __test_addresses_outside_segment_sidt_es(); + __test_addresses_outside_segment_sldt_es(); + __test_addresses_outside_segment_smsw_fs(); + __test_addresses_outside_segment_str_fs(); + __test_addresses_outside_segment_sgdt_fs(); + __test_addresses_outside_segment_sidt_fs(); + __test_addresses_outside_segment_sldt_fs(); +#ifdef TEST_GS + __test_addresses_outside_segment_smsw_gs(); + __test_addresses_outside_segment_str_gs(); + __test_addresses_outside_segment_sgdt_gs(); + __test_addresses_outside_segment_sidt_gs(); + __test_addresses_outside_segment_sldt_gs(); +#endif +} +#endif + +void usage(void) +{ + printf("Usage: [m][l][r][n][d][a]\n"); + printf("m Test test_maperr_pf\n"); + printf("l Test test_lock_prefix\n"); + printf("r Test test_register_operand\n"); + printf("n Test test_null_segment_selectors(TODO)\n"); + printf("d Test test_addresses_outside_segment(TODO)\n"); + printf("a Test all\n"); +} + +int main (int argc, char *argv[]) +{ + struct sigaction action; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signal_handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + char parm; + + if (argc == 1) + { + usage(); + exit(1); + } + else if (argc == 2) + { + sscanf(argv[1], "%c", &parm); + pr_info("1 parameters: parm=%c\n", parm); + } + else + { + sscanf(argv[1], "%c", &parm); + pr_info("Just get parm=%c\n", parm); + } + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler for SIGSEGV!\n"); + exit(1); + } + + if (sigaction(SIGILL, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler SIGILL!\n"); + exit(1); + } + + switch (parm) + { + case 'a' : pr_info("Test all.\n"); + pr_info("***Test test_maperr_pf next***\n"); + test_maperr_pf(); + pr_info("***Test test_lock_prefix next***\n"); + test_lock_prefix(); + pr_info("***Test test_register_operand next***\n"); + test_register_operand(); + pr_info("***Test test_null_segment_selectors next***\n"); + test_null_segment_selectors(); + pr_info("***Test test_addresses_outside_segment next***\n"); + test_addresses_outside_segment(); + break; + case 'm' : pr_info("***Test test_maperr_pf next***\n"); + test_maperr_pf(); + break; + case 'l' : pr_info("***Test test_lock_prefix next***\n"); + test_lock_prefix(); + break; + case 'r' : pr_info("***Test test_register_operand next***\n"); + test_register_operand(); + break; + case 'n' : pr_info("***Test test_null_segment_selectors next***"); + test_null_segment_selectors(); + break; + case 'd' : pr_info("***Test test_addresses_outside_segment next***"); + test_addresses_outside_segment(); + break; + default: usage(); + exit(1); + } + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal SIGSEGV handler!\n"); + print_results(); + return 1; + } + + if (sigaction(SIGILL, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal SIGILL handler!\n"); + print_results(); + return 1; + } + + print_results(); + return 0; +} diff --git a/meta-luv/recipes-core/umip/files/umip_ldt_16.c b/meta-luv/recipes-core/umip/files/umip_ldt_16.c new file mode 100644 index 00000000000..cf30ce86414 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_ldt_16.c @@ -0,0 +1,357 @@ +/* Test cases for UMIP */ +/* Copyright Intel Corporation 2017 */ + +#include +#include +#include +#include +#include +#include +#include +#include "umip_test_defs.h" +#include "test_umip_ldt_16.h" +#include "test_umip_code_16.h" + +extern unsigned char test_umip[], test_umip_end[]; +extern unsigned char interim[], interim_start[], interim_end[]; +extern unsigned char finish_testing[]; +extern unsigned char data[SEGMENT_SIZE]; +extern unsigned char data_es[SEGMENT_SIZE]; +extern unsigned char data_fs[SEGMENT_SIZE]; +extern unsigned char data_gs[SEGMENT_SIZE]; +extern unsigned char stack_32[SEGMENT_SIZE]; +extern unsigned char stack[SEGMENT_SIZE]; +extern int exit_on_signal; +unsigned short cs_orig; + +#define CODE_DESC_INDEX 1 +#define CODE_16_DESC_INDEX 2 +#define DATA_DESC_INDEX 3 +#define STACK_16_DESC_INDEX 4 +#define STACK_DESC_INDEX 5 +#define DATA_ES_DESC_INDEX 6 +#define DATA_FS_DESC_INDEX 7 +#define DATA_GS_DESC_INDEX 8 + +#define RPL3 3 +#define TI_LDT 1 +#define SEGMENT_SELECTOR(index) (RPL3 | (TI_LDT << 2) | (index << 3)) + +int test_passed, test_failed, test_errors; + +asm(".pushsection .rodata\n\t" + "interim:\n\t" + /* this is the return point */ + "interim_return:\n\t" + /* restore our own stack */ + "mov %ebx, %ss\n\t" + "mov %eax, %esp\n\t" + /* restore ss of caller */ + "pop %ebx\n\t" + /* restore esp of caller*/ + "pop %eax\n\t" + /* prepare to return, set IP, CS is already in stack */ + "push $finish_testing\n\t" + "retf\n\t" + /* this is the interim start */ + "interim_start:\n\t" + /* setup stack */ + "mov $4096, %esp\n\t" + "mov %ecx, %ss\n\t" + /* save old cs */ + "push %edx\n\t" + /* save old esp */ + "push %eax\n\t" + /* save old ss */ + "push %ebx\n\t" + /* prepare to jump */ + /* pass current stack pointer, ss and cs */ + /* this is to know where we need to return to */ + "mov %esp, %eax\n\t" + "mov %ss, %ebx\n\t" + "mov %cs, %edx\n\t" + "push %edi\n\t" + "push $0\n\t" + "retf\n\t" + "interim_end:\n\t" + ".popsection\n\t" + ); + +static int setup_data_segments() +{ + int ret; + struct user_desc desc = { + .entry_number = 0, + .base_addr = 0, + .limit = SEGMENT_SIZE, + .seg_32bit = 0, + .contents = 0, /* data */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 1 + }; + + desc.entry_number = STACK_DESC_INDEX; + desc.base_addr = (unsigned long)&stack_32; + + memset(stack_32, 0x88, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + printf("Failed to install stack semgnet [%d].\n", ret); + return ret; + } + + desc.entry_number = STACK_16_DESC_INDEX; + desc.base_addr = (unsigned long)&stack; + + memset(stack, 0x44, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install stack semgnet [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_DESC_INDEX; + desc.base_addr = (unsigned long)&data; + + memset(data, 0x99, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_ES_DESC_INDEX; + desc.base_addr = (unsigned long)&data_es; + + memset(data_es, 0x77, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_FS_DESC_INDEX; + desc.base_addr = (unsigned long)&data_fs; + + memset(data_fs, 0x66, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_GS_DESC_INDEX; + desc.base_addr = (unsigned long)&data_gs; + + memset(data_gs, 0x55, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + return 0; +} + +int run_umip_ldt_test(void) +{ + int ret; + unsigned short interim_cs, interim_ss; + unsigned short test_cs_16, test_ds_16, test_ss_16; + unsigned short test_es_16, test_fs_16, test_gs_16; + unsigned long interim_start_addr; + unsigned char *code_interim, *code_16; + struct sigaction action; + + struct user_desc code_desc = { + .entry_number = CODE_DESC_INDEX, + .seg_32bit = 1, + .contents = 2, /* non-conforming */ + .read_exec_only = 1, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 1 + }; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signal_handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + exit_on_signal = 1; + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler!"); + goto err_out; + } + + code_interim = mmap(NULL, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (!code_interim) { + pr_error(test_errors, "Failed to allocate memory for interim code segment!\n"); + goto err_out; + } + + memcpy(code_interim, interim, interim_end - interim); + + code_16 = mmap(NULL, CODE_MEM_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (!code_16) { + pr_error(test_errors, "Failed to allocate memory for code segment!\n"); + goto err_out; + } + + memcpy(code_16, test_umip, test_umip_end - test_umip); + + /* install our 32-bit intermediate code segment */ + code_desc.base_addr = (unsigned long)code_interim; + code_desc.limit = interim_end - interim + 100; + + ret = syscall(SYS_modify_ldt, 1, &code_desc, sizeof(code_desc)); + if (ret) { + pr_error(test_errors, "Failed to install interim code segment [%d].\n", ret); + goto err_out; + } + + /* install our 16-bit code segment */ + code_desc.entry_number = CODE_16_DESC_INDEX, + code_desc.base_addr = (unsigned long)code_16; + code_desc.seg_32bit = 0, + code_desc.limit = test_umip_end - test_umip + 100; + + ret = syscall(SYS_modify_ldt, 1, &code_desc, sizeof(code_desc)); + if (ret) { + pr_error(test_errors, "Failed to install 16-bit code segment [%d].\n", ret); + goto err_out; + } + + if (setup_data_segments()) { + pr_error(test_errors, "Failed to setup segments [%d].\n", ret); + goto err_out; + } + + interim_cs = SEGMENT_SELECTOR(CODE_DESC_INDEX); + interim_ss = SEGMENT_SELECTOR(STACK_DESC_INDEX); + test_cs_16 = SEGMENT_SELECTOR(CODE_16_DESC_INDEX); + test_ss_16 = SEGMENT_SELECTOR(STACK_16_DESC_INDEX); + test_ds_16 = SEGMENT_SELECTOR(DATA_DESC_INDEX); + test_es_16 = SEGMENT_SELECTOR(DATA_ES_DESC_INDEX); + test_fs_16 = SEGMENT_SELECTOR(DATA_FS_DESC_INDEX); + test_gs_16 = SEGMENT_SELECTOR(DATA_GS_DESC_INDEX); + + /* + * We cannot use the object's interim_start label as it we + * have copied our code to mmap'ed memory. Thus, we need + * calculate it as an offset since the beginning of the + * section + */ + interim_start_addr = interim_start - interim; + + asm(/* make a backup of everything */ + "push %%ds\n\t" + "push %%es\n\t" + "push %%fs\n\t" + "push %%gs\n\t" + "push %%eax\n\t" + "push %%ebx\n\t" + "push %%ecx\n\t" + "push %%edx\n\t" + "push %%edi\n\t" + "push %%esi\n\t" + "push %%ebp\n\t" + /* set new data segment */ + "mov %[test_ds_16], %%ds\n\t" + "mov %[test_es_16], %%es\n\t" + "mov %[test_fs_16], %%fs\n\t" + "mov %[test_gs_16], %%gs\n\t" + /* + * Save current stack settings and pass them to the new code segment + * via registers. We will save these as soon as we setup a new stack + * segment. + */ + "mov %%esp, %%eax\n\t" + "mov %%ss, %%ebx\n\t" + /* + * Give interim code the new stack segment. We cannot set it here as + * we need it to jump to the test code via retf + */ + "mov %[interim_ss], %%ecx\n\t" + /* + * Pass the code segment selector to the interim code so that it knows + * where to return + */ + "mov %%cs, %%edx\n\t" + /* + * Pass the code and stacks segment selectors of the 16-bit code + * as we only know them from this context. + */ + "mov %[test_ss_16], %%esi\n\t" + "mov %[test_cs_16], %%edi\n\t" + /* + *ljmp only takes constants. Instead use retf, which takes + * instruction pointer and code segment selector from the stack + */ + "push %[interim_cs]\n\t" + "push %[interim_start_addr]\n\t" + "retf \n\t" + "finish_testing:\n\t" + /* restore our stack */ + "mov %%ebx, %%ss\n\t" + "mov %%eax, %%esp\n\t" + /* restore everything */ + "pop %%ebp\n\t" + "pop %%esi\n\t" + "pop %%edi\n\t" + "pop %%edx\n\t" + "pop %%ecx\n\t" + "pop %%ebx\n\t" + "pop %%eax\n\t" + "pop %%gs\n\t" + "pop %%fs\n\t" + "pop %%es\n\t" + "pop %%ds\n\t" + : + : [test_ds_16]"m"(test_ds_16), [test_es_16]"m"(test_es_16), + [test_fs_16]"m"(test_fs_16), [test_gs_16]"m"(test_gs_16), + [interim_ss]"m"(interim_ss), [test_ss_16]"m"(test_ss_16), + [test_cs_16]"m"(test_cs_16), [interim_cs]"m"(interim_cs), + [interim_start_addr]"m"(interim_start_addr) + ); + + pr_info("===Test results===\n"); + + check_results(); + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal handler!"); + goto err_out; + } + + printf("Exiting...\n"); + print_results(); + return 0; +err_out: + pr_error(test_errors, "Could not run tests\n"); + print_results(); + return 1; + +}; + +int main(void) +{ + return run_umip_ldt_test(); +} diff --git a/meta-luv/recipes-core/umip/files/umip_ldt_32.c b/meta-luv/recipes-core/umip/files/umip_ldt_32.c new file mode 100644 index 00000000000..1e5ea94a08a --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_ldt_32.c @@ -0,0 +1,266 @@ +/* Test cases for UMIP */ +/* Copyright Intel Corporation 2017 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "umip_test_defs.h" +#include "test_umip_ldt_32.h" +#include "test_umip_code_32.h" + +extern unsigned char test_umip[], test_umip_end[]; +extern unsigned char finish_testing[]; +extern unsigned char data[SEGMENT_SIZE]; +extern unsigned char data_es[SEGMENT_SIZE]; +extern unsigned char data_fs[SEGMENT_SIZE]; +extern unsigned char data_gs[SEGMENT_SIZE]; +extern unsigned char stack[SEGMENT_SIZE]; +extern int exit_on_signal; +unsigned short cs_orig; + +#define CODE_DESC_INDEX 1 +#define DATA_DESC_INDEX 2 +#define STACK_DESC_INDEX 3 +#define DATA_ES_DESC_INDEX 4 +#define DATA_FS_DESC_INDEX 5 +#define DATA_GS_DESC_INDEX 6 + +#define RPL3 3 +#define TI_LDT 1 +#define SEGMENT_SELECTOR(index) (RPL3 | (TI_LDT << 2) | (index << 3)) + +extern int test_passed, test_failed, test_errors; + +static int setup_data_segments() +{ + int ret; + struct user_desc desc = { + .entry_number = 0, + .base_addr = 0, + .limit = SEGMENT_SIZE, + .seg_32bit = 1, + .contents = 0, /* data */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 1 + }; + + desc.entry_number = STACK_DESC_INDEX; + desc.base_addr = (unsigned long)&stack; + + memset(stack, 0x88, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install stack semgnet [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_DESC_INDEX; + desc.base_addr = (unsigned long)&data; + + memset(data, 0x99, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_ES_DESC_INDEX; + desc.base_addr = (unsigned long)&data_es; + + memset(data_es, 0x77, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_FS_DESC_INDEX; + desc.base_addr = (unsigned long)&data_fs; + + memset(data_fs, 0x66, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_GS_DESC_INDEX; + desc.base_addr = (unsigned long)&data_gs; + + memset(data_gs, 0x55, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error(test_errors, "Failed to install data segment [%d].\n", ret); + return ret; + } + + return 0; +} + +int run_umip_ldt_test(void) +{ + int ret; + unsigned short test_cs, test_ds, test_ss; + unsigned short test_es, test_fs, test_gs; + struct sigaction action; + unsigned char *code; + + struct user_desc code_desc = { + .entry_number = CODE_DESC_INDEX, + .seg_32bit = 1, + .contents = 2, /* non-conforming */ + .read_exec_only = 1, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 1 + }; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signal_handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + exit_on_signal = 1; + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler!"); + goto err_out; + } + + code = mmap(NULL, CODE_MEM_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (!code) { + pr_error(test_errors, "Failed to allocate memory for code segment!\n"); + goto err_out; + } + + memcpy(code, test_umip, test_umip_end - test_umip); + + code_desc.base_addr = (unsigned long)code; + code_desc.limit = test_umip_end - test_umip + 100; + + ret = syscall(SYS_modify_ldt, 1, &code_desc, sizeof(code_desc)); + if (ret) { + pr_error(test_errors, "Failed to install code segment [%d].\n", ret); + goto err_out; + } + + if (setup_data_segments()) { + pr_error(test_errors, "Failed to setup segments [%d].\n", ret); + goto err_out; + } + + test_cs = SEGMENT_SELECTOR(CODE_DESC_INDEX); + test_ds = SEGMENT_SELECTOR(DATA_DESC_INDEX); + test_ss = SEGMENT_SELECTOR(STACK_DESC_INDEX); + test_es = SEGMENT_SELECTOR(DATA_ES_DESC_INDEX); + test_fs = SEGMENT_SELECTOR(DATA_FS_DESC_INDEX); + test_gs = SEGMENT_SELECTOR(DATA_GS_DESC_INDEX); + + asm(/* make a backup of everything */ + "push %%ds\n\t" + "push %%es\n\t" + "push %%fs\n\t" + "push %%gs\n\t" + "push %%eax\n\t" + "push %%ebx\n\t" + "push %%ecx\n\t" + "push %%edx\n\t" + "push %%edi\n\t" + "push %%esi\n\t" + "push %%ebp\n\t" + /* set new data segment */ + "mov %0, %%ds\n\t" + "mov %1, %%es\n\t" + "mov %2, %%fs\n\t" + "mov %3, %%gs\n\t" + /* + * Save current stack settings and pass them to the new code segment + * via registers. We will save these as soon as we setup a new stack + * segment. + */ + "mov %%esp, %%eax\n\t" + "mov %%ss, %%ebx\n\t" + /* + * Give test code the new stack segment. We cannot set it here as + * we need it to jump to the test code via retf + */ + "mov %4, %%ecx\n\t" + /* + * Pass the code segment selector to the new code so that it knows + * where to return + */ + "mov %%cs, %%edx\n\t" + /* + * ljmp only takes constants. Instead use retf, which pops + * instruction pointer and code segment selector from the stack + */ + "push %5\n\t" + /* jump to the beginning of the new segment */ + "push $0\n\t" + /* Everything is set. Make the jump */ + "retf \n\t" + /* After running tests, we return here */ + "finish_testing:\n\t" + /* restore our stack */ + "mov %%ebx, %%ss\n\t" + "mov %%eax, %%esp\n\t" + /* restore everything */ + "pop %%ebp\n\t" + "pop %%esi\n\t" + "pop %%edi\n\t" + "pop %%edx\n\t" + "pop %%ecx\n\t" + "pop %%ebx\n\t" + "pop %%eax\n\t" + "pop %%gs\n\t" + "pop %%fs\n\t" + "pop %%es\n\t" + "pop %%ds\n\t" + : + :"m"(test_ds), "m"(test_es), "m"(test_fs), "m"(test_gs), + "m"(test_ss), "m"(test_cs) + ); + + pr_info("===Test results===\n"); + check_results(); + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal handler!"); + print_results(); + exit(1); + } + + pr_info("Exiting...\n"); + + print_results(); + return 0; +err_out: + pr_error(test_errors, "Could not run tests\n"); + print_results(); + return 1; + +}; + +int main(void) +{ + return run_umip_ldt_test(); +} diff --git a/meta-luv/recipes-core/umip/files/umip_ldt_64.c b/meta-luv/recipes-core/umip/files/umip_ldt_64.c new file mode 100644 index 00000000000..df2551c7dbe --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_ldt_64.c @@ -0,0 +1,204 @@ +/* Test cases for UMIP */ +/* Copyright Intel Corporation 2017 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "umip_test_defs.h" +#include "test_umip_ldt_64.h" +#include "test_umip_code_64.h" + +extern unsigned char test_umip[], test_umip_end[]; +extern unsigned char finish_testing[]; +extern unsigned char data_fs[SEGMENT_SIZE]; +extern unsigned char data_gs[SEGMENT_SIZE]; +extern int exit_on_signal; +extern void (*cleanup)(void); +unsigned long old_fsbase, old_gsbase; +unsigned short old_fs, old_gs; + +#define CODE_DESC_INDEX 1 +#define DATA_FS_DESC_INDEX 2 +#define DATA_GS_DESC_INDEX 3 + +#define RPL3 3 +#define TI_LDT 1 +#define SEGMENT_SELECTOR(index) (RPL3 | (TI_LDT << 2) | (index << 3)) + +extern int test_passed, test_failed, test_errors; + +static int setup_data_segments() +{ + int ret; + struct user_desc desc = { + .entry_number = 0, + .base_addr = 0, + .limit = SEGMENT_SIZE, + .seg_32bit = 1, + .contents = 0, /* data */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 1 + }; + + desc.entry_number = DATA_FS_DESC_INDEX; + desc.base_addr = (unsigned long)&data_fs; + + memset(data_fs, 0x66, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + printf("Failed to install data segment [%d].\n", ret); + return ret; + } + + desc.entry_number = DATA_GS_DESC_INDEX; + desc.base_addr = (unsigned long)&data_gs; + + memset(data_gs, 0x55, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + printf("Failed to install data segment [%d].\n", ret); + return ret; + } + + return 0; +} + +static void cleanup_segments(void) +{ + asm volatile("movw %0,%%fs" : :"m" (old_fs)); + asm volatile("movw %0, %%gs" : : "m" (old_gs)); + + syscall(SYS_arch_prctl, ARCH_SET_FS, old_fsbase); + syscall(SYS_arch_prctl, ARCH_SET_GS, old_gsbase); +} + +int main(void) +{ + int ret; + unsigned short test_fs, test_gs; + unsigned char *code; + struct sigaction action; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signal_handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + +#ifdef EMULATE_ALL + exit_on_signal = 1; +#else + exit_on_signal = 2; +#endif + + cleanup = cleanup_segments; + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler!"); + goto err_out; + } + + code = mmap(NULL, CODE_MEM_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_PRIVATE | MAP_32BIT | MAP_ANONYMOUS, -1, 0); + if (!code) { + printf("Failed to allocate memory for code segment!\n"); + goto err_out; + } + + memcpy(code, test_umip, test_umip_end - test_umip); + + test_fs = SEGMENT_SELECTOR(DATA_FS_DESC_INDEX); + test_gs = SEGMENT_SELECTOR(DATA_GS_DESC_INDEX); + + ret = setup_data_segments(); + if (ret) { + pr_error(test_errors, "Failed to setup segments [%d].\n", ret); + goto err_out; + } + + syscall(SYS_arch_prctl, ARCH_GET_FS, &old_fsbase); + syscall(SYS_arch_prctl, ARCH_GET_GS, &old_gsbase); + + asm volatile("movw %%fs, %0" : "=m" (old_fs)); + asm volatile("movw %%gs, %0" : "=m" (old_gs)); + + syscall(SYS_arch_prctl, ARCH_SET_FS, (unsigned long)data_fs); + syscall(SYS_arch_prctl, ARCH_SET_GS, (unsigned long)data_gs); + + asm(/* make a backup of everything */ + "push %%rax\n\t" + "push %%rbx\n\t" + "push %%rcx\n\t" + "push %%rdx\n\t" + "push %%rdi\n\t" + "push %%rsi\n\t" + "push %%rbp\n\t" + "push %%r8\n\t" + "push %%r9\n\t" + "push %%r10\n\t" + "push %%r11\n\t" + "push %%r12\n\t" + "push %%r13\n\t" + "push %%r14\n\t" + "push %%r15\n\t" + /* set new data segment */ + /* jump to test code */ + "call *%0\n\t" + /* After running tests, we return here */ + "finish_testing:\n\t" + /* restore everything */ + "pop %%r15\n\t" + "pop %%r14\n\t" + "pop %%r13\n\t" + "pop %%r12\n\t" + "pop %%r11\n\t" + "pop %%r10\n\t" + "pop %%r9\n\t" + "pop %%r8\n\t" + "pop %%rbp\n\t" + "pop %%rsi\n\t" + "pop %%rdi\n\t" + "pop %%rdx\n\t" + "pop %%rcx\n\t" + "pop %%rbx\n\t" + "pop %%rax\n\t" + : + :"m"(code) + ); + + cleanup_segments(); + + printf("===Test results===\n"); + check_results(); + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal handler!"); + print_results(); + exit(1); + } + printf("Exiting...\n"); + print_results(); + + return 0; +err_out: + pr_error(test_errors, "Could not run tests\n"); + print_results(); + + printf("Now you will see a segmentation fault. This is under investigation.\n"); + return 1; +}; + diff --git a/meta-luv/recipes-core/umip/files/umip_test_basic.c b/meta-luv/recipes-core/umip/files/umip_test_basic.c new file mode 100644 index 00000000000..24bcf8afe75 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_basic.c @@ -0,0 +1,339 @@ +/* + * tests for Intel User-Mode Execution Prevention + * + * GPLv2 + */ + +#include +#include +#include +#include +#include +#include "umip_test_defs.h" + +#ifdef __x86_64__ +#define GDTR_LEN 10 +#define IDTR_LEN 10 +#else +#define GDTR_LEN 6 +#define IDTR_LEN 6 +#endif + +int test_passed, test_failed, test_errors; +extern sig_atomic_t got_signal, got_sigcode; + +static void call_sgdt() +{ + unsigned char val[GDTR_LEN]; + unsigned long base = INIT_VAL(89898989); + unsigned short limit = 0x3d3d; + int i, exp_signum, exp_sigcode; + + got_signal = 0; + got_sigcode = 0; + INIT_EXPECTED_SIGNAL(exp_signum, 0, exp_sigcode, 0); + + for (i = 0; i < GDTR_LEN; i++) + val[i] = 0; + pr_info("Will issue SGDT and save at [%p]\n", val); + asm volatile("sgdt %0\n" NOP_SLED : "=m" (val)); + + if(inspect_signal(exp_signum, exp_sigcode)) + return; + + limit = val[1] << 8 | val[0]; + pr_info("GDT Limit [0x%04x]\n", limit); + + if (limit == expected_gdt.limit) + pr_pass(test_passed, "Expected limit value\n"); + else + pr_fail(test_failed, "Unexpected limit value\n"); + +#if 0 + for (i = 0; i < (GDTR_LEN -2); i++) + base |= (unsigned long) val[i+2] << ((i * 8)); +#else + base = *(unsigned long *)(val + 2); +#endif + pr_info("GDT Base [0x%016lx]\n", base); + + if (base == expected_gdt.base) + pr_pass(test_passed, "Expected base value\n"); + else + pr_fail(test_failed, "Unexpected base value\n"); +} + +static void call_sidt() +{ + unsigned char val[IDTR_LEN]; + unsigned long base = INIT_VAL(73737373); + unsigned short limit = 0x9696; + int i, exp_signum, exp_sigcode; + + got_signal = 0; + got_sigcode = 0; + INIT_EXPECTED_SIGNAL(exp_signum, 0, exp_sigcode, 0); + + for (i = 0; i < IDTR_LEN; i++) + val[i] = 0; + pr_info("Will issue SIDT and save at [%p]\n", val); + asm volatile("sidt %0\n" NOP_SLED : "=m" (val)); + + if(inspect_signal(exp_signum, exp_sigcode)) + return; + + limit = val[1] << 8 | val[0]; + pr_info("IDT Limit [0x%04x]\n", limit); + + if (limit == expected_idt.limit) + pr_pass(test_passed, "Expected limit value\n"); + else + pr_fail(test_failed, "Unexpected limit value\n"); + +#if 0 + for (i = 0; i < (IDTR_LEN -2); i++) + base |= (unsigned long) val[i+2] << ((i * 8)); +#else + base = *(unsigned long *)(val + 2); +#endif + pr_info("IDT Base [0x%016lx]\n", base); + + if (base == expected_idt.base) + pr_pass(test_passed, "Expected base value\n"); + else + pr_fail(test_failed, "Unexpected base value\n"); +} + +static void call_sldt() +{ + unsigned long val = INIT_VAL(a1a1a1a1); + unsigned long init_val = INIT_VAL(a1a1a1a1); + /* if operand is memory, result is 16-bit */ + unsigned short mask = 0xffff; + int exp_signum, exp_sigcode; + + got_signal = 0; + got_sigcode = 0; + INIT_EXPECTED_SIGNAL_STR_SLDT(exp_signum, 0, exp_sigcode, 0); + + pr_info("Will issue SLDT and save at [%p]\n", &val); + asm volatile("sldt %0\n" NOP_SLED : "=m" (val)); + + if(inspect_signal(exp_signum, exp_sigcode)) + return; + + pr_info("SS for LDT[0x%08lx]\n", val); + + /* + * Check that the bits that are supposed to change does so + * as well as that the bits that are not supposed to change + * does not change. + */ \ + if ((val & mask) == (expected_ldt & mask) && + (val & ~mask) == (init_val & ~mask)) + pr_pass(test_passed, "Obtained expected value\n"); + else + pr_fail(test_failed, "Obtained unexpected value\n"); +} + +static void call_smsw() +{ + unsigned long val = INIT_VAL(a2a2a2a2); + unsigned long init_val = INIT_VAL(a2a2a2a2); + unsigned short mask = 0xffff; + int exp_signum, exp_sigcode; + + got_signal = 0; + got_sigcode = 0; + INIT_EXPECTED_SIGNAL(exp_signum, 0, exp_sigcode, 0); + + + pr_info("Will issue SMSW and save at [%p]\n", &val); + asm volatile("smsw %0\n" NOP_SLED : "=m" (val)); + + if(inspect_signal(exp_signum, exp_sigcode)) + return; + + pr_info("CR0[0x%08lx]\n", val); + + /* + * Check that the bits that are supposed to change does so + * as well as that the bits that are not supposed to change + * does not change. + */ \ + if ((val & mask) == (expected_msw & mask) && + (val & ~mask) == (init_val & ~mask)) + pr_pass(test_passed, "Obtained expected value\n"); + else + pr_fail(test_failed, "Obtained unexpected value\n"); +} + +static void call_str() +{ + unsigned int val32 = 0xa4a4a4a4; + unsigned int init_val32 = 0xa4a4a4a4; + unsigned short val16 = 0xa5a5; + unsigned short init_val16 = 0xa5a5; + int exp_signum, exp_sigcode; + + got_signal = 0; + got_sigcode = 0; + INIT_EXPECTED_SIGNAL_STR_SLDT(exp_signum, 0, exp_sigcode, 0); + +#if __x86_64__ + unsigned long val64 = 0xa3a3a3a3a3a3a3a3; + unsigned long init_val64 = 0xa3a3a3a3a3a3a3a3; + + pr_info("Will issue STR and save at m64[0x%p]\n", &val64); + asm volatile("str %0\n" NOP_SLED : "=m" (val64)); + + if(inspect_signal(exp_signum, exp_sigcode)) + goto test_m32; + + pr_info("SS for TSS[0x%016lx]\n", val64); + + /* + * Check that the bits that are supposed to change does so + * as well as that the bits that are not supposed to change + * does not change. Since operand is memory, value will be + * 16-bit. + */ + if ((val64 & 0xffff) == (expected_tr & 0xffff) && + (val64 & ~0xffff) == (init_val64 & ~0xffff)) + pr_pass(test_passed, "Obtained 64-bit expected value\n"); + else + pr_fail(test_failed, "Obtained 64-bit unexpected value\n"); + +test_m32: +#endif + + got_signal = 0; + got_sigcode = 0; + + pr_info("Will issue STR and save at m32[0x%p]\n", &val32); + asm volatile("str %0\n" NOP_SLED : "=m" (val32)); + + if(inspect_signal(exp_signum, exp_sigcode)) + goto test_m16; + + pr_info("SS for TSS[0x%08x]\n", val32); + + /* + * Check that the bits that are supposed to change does so + * as well as that the bits that are not supposed to change + * does not change. Since operand is memory, value will be + * 16-bit. + */ + if ((val32 & 0xffff) == (expected_tr & 0xffff) && + (val32 & ~0xffff) == (init_val32 & ~0xffff)) + pr_pass(test_passed, "Obtained 32-bit expected value\n"); + else + pr_fail(test_failed, "Obtained 32-bit unexpected value\n"); + +test_m16: + got_signal = 0; + got_sigcode = 0; + + pr_info("Will issue STR and save at m16[0x%p]\n", &val16); + asm volatile("str %0\n" NOP_SLED : "=m" (val16)); + + if(inspect_signal(exp_signum, exp_sigcode)) + return; + + pr_info("SS for TSS[0x%04x]\n", val16); + + /* + * Check that the bits that are supposed to change does so + * as well as that the bits that are not supposed to change + * does not change. Since operand is memory, value will be + * 16-bit. + */ + if ((val16 & 0xffff) == (expected_tr & 0xffff) && + (val16 & ~0xffff) == (init_val16 & ~0xffff)) + pr_pass(test_passed, "Obtained 16-bit expected value\n"); + else + pr_fail(test_failed, "Obtained 16-bit unexpected value\n"); + +} + +void usage(void) +{ + printf("Usage: [g][i][l][m][t][a]\n"); + printf("g Test sgdt\n"); + printf("i Test sidt\n"); + printf("l Test sldt\n"); + printf("m Test smsw\n"); + printf("t Test str\n"); + printf("a Test all\n"); +} + +int main(int argc, char *argv[]) +{ + struct sigaction action; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signal_handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + char parm; + + if (argc == 1) + { + usage(); + exit(1); + } + else if (argc == 2) + { + sscanf(argv[1], "%c", &parm); + pr_info("1 parameters: parm=%c\n", parm); + } + else + { + sscanf(argv[1], "%c", &parm); + pr_info("Just get parm=%c\n", parm); + } + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler!"); + print_results(); + exit(1); + } + + switch (parm) + { + case 'a' : pr_info("Test all.\n"); + call_sgdt(); + call_sidt(); + call_sldt(); + call_smsw(); + call_str(); + break; + case 'g' : call_sgdt(); + break; + case 'i' : call_sidt(); + break; + case 'l' : call_sldt(); + break; + case 'm' : call_smsw(); + break; + case 't' : call_str(); + break; + default: usage(); + exit(1); + } + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal handler!"); + print_results(); + exit(1); + } + + print_results(); + return 0; +} diff --git a/meta-luv/recipes-core/umip/files/umip_test_defs.h b/meta-luv/recipes-core/umip/files/umip_test_defs.h new file mode 100644 index 00000000000..8e613e496e8 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_defs.h @@ -0,0 +1,125 @@ +#ifndef _UMIP_TEST_DEFS_H +#define _UMIP_TEST_DEFS_H +#include +#include + +#define TEST_PASS "\x1b[32m[pass]\x1b[0m " +#define TEST_FAIL "\x1b[31m[FAIL]\x1b[0m " +#define TEST_INFO "\x1b[34m[info]\x1b[0m " +#define TEST_ERROR "\x1b[33m[ERROR]\x1b[0m " + +#define pr_pass(pass_ctr, ...) do{ printf(TEST_PASS __VA_ARGS__); pass_ctr++; } while(0) +#define pr_fail(fail_ctr, ...) do{ printf(TEST_FAIL __VA_ARGS__); fail_ctr++; } while(0) +#define pr_info(...) printf(TEST_INFO __VA_ARGS__) +#define pr_error(error_ctr, ...) do{ printf(TEST_ERROR __VA_ARGS__); error_ctr++; } while(0) + +/* + * Use this definiton to check for results that fit in a single variable + * (e.g., char, short, int, long, double) + */ +#define pr_result(result, expected, text, pass_ctr, fail_ctr) \ + do{ \ + if (result == expected) \ + pr_pass(pass_ctr, text); \ + else \ + pr_fail(fail_ctr, text); \ + printf("Got:[0x%x]Exp[0x%x]\n", result, expected); \ + } while(0) + +/* + * Use this definiton to check for results that in struct table_desc + * (e.g., char, short, int, long, double) + */ +#define pr_result_table(result, expected, text, pass_ctr, fail_ctr) \ + do{ \ + if ((result->base == expected->base) && \ + (result->limit == expected->limit)) \ + pr_pass(pass_ctr, text); \ + else \ + pr_fail(fail_ctr, text); \ + printf("Got:Base[0x%lx]Limit[0x%x]ExpBase[0x%lx]Limit[0x%x]\n", \ + got->base, got->limit, \ + expected->base, expected->limit); \ + } while(0) + +#ifdef __x86_64__ +#define PRINT_BITNESS pr_info("This binary uses 64-bit code\n") +#define INIT_VAL(val) (0x##val##val) +#else +#define PRINT_BITNESS pr_info("This binary uses 32-bit code\n") +#define INIT_VAL(val) (0x##val) +#endif + +#define EXPECTED_SMSW 0x80050033 +#define EXPECTED_SLDT 0x0 +#define EXPECTED_STR 0x0 +#define EXPECTED_GDT_BASE 0xfffe0000 +#define EXPECTED_GDT_LIMIT 0x0 +#define EXPECTED_IDT_BASE 0xffff0000 +#define EXPECTED_IDT_LIMIT 0x0 + +/* + * EMULATE_ALL implies that all the UMIP-protected instructions are emulated. + * If not defined, the following rules apply: + * + UMIP-protected instructions are not emulated for 64-bit processes. This + * means that we always should get a SIGSEGV signal with code SI_KERNEL. + * + In 32-bit processes, only SGDT, SIDT and SMSW are emulated, STR and + * SLDT should cause a SIGSEGV signal with code SI_CODE. + */ +#ifdef EMULATE_ALL +#define INIT_EXPECTED_SIGNAL(signum, exp_signum, sigcode, exp_sigcode) \ + do{ \ + signum = exp_signum; \ + sigcode = exp_sigcode; \ + } while (0) +#else /* EMULATE_ALL */ +#ifdef __x86_64__ +#define INIT_EXPECTED_SIGNAL(signum, exp_signum, sigcode, exp_sigcode) \ + do{ \ + signum = SIGSEGV; \ + sigcode = SI_KERNEL; \ + } while(0) +#else /* __x86_64__ */ +#define INIT_EXPECTED_SIGNAL(signum, exp_signum, sigcode, exp_sigcode) \ + do{ \ + signum = exp_signum; \ + sigcode = exp_sigcode; \ + } while(0) +#endif /* __x86_64__ */ +#endif /* EMULATE_ALL */ + +#ifdef EMULATE_ALL +#define INIT_EXPECTED_SIGNAL_STR_SLDT(signum, exp_signum, sigcode, exp_sigcode) \ + INIT_EXPECTED_SIGNAL(signum, exp_signum, sigcode, exp_sigcode) +#else +#define INIT_EXPECTED_SIGNAL_STR_SLDT(signum, exp_signum, sigcode, exp_sigcode) \ + INIT_EXPECTED_SIGNAL(signum, SIGSEGV, sigcode, SI_KERNEL) +#endif + +#define NOP_SLED "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" \ + "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" "nop\n" + +struct table_desc { + unsigned short limit; + unsigned long base; +} __attribute__((packed)); + +static const unsigned long expected_msw = EXPECTED_SMSW; +static const unsigned long expected_ldt = EXPECTED_SLDT; +static const unsigned long expected_tr = EXPECTED_STR; + +static const struct table_desc expected_gdt = { + .limit = EXPECTED_GDT_LIMIT, + .base = EXPECTED_GDT_BASE +}; + +static const struct table_desc expected_idt = { + .limit = EXPECTED_IDT_LIMIT, + .base = EXPECTED_IDT_BASE +}; + +void print_results(void); +int inspect_signal(int exp_signum, int exp_sigcode); +void signal_handler(int signum, siginfo_t *info, void *ctx_void); + +#endif /* _UMIP_TEST_DEFS_H */ diff --git a/meta-luv/recipes-core/umip/files/umip_test_gen_16.py b/meta-luv/recipes-core/umip/files/umip_test_gen_16.py new file mode 100644 index 00000000000..b196c62dbaa --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_gen_16.py @@ -0,0 +1,435 @@ +""" Test-case generator for UMIP +Copyright Intel Corporation 2017 + +This file generates opcdoes for all (well, most) of the combinations +of memory operands for the UMIP-protected instructions. This includes +all the ModRM values and segments. + +TODO: Add support for 16-bit address encodings +TODO: Add support for SiB address encodings""" + +import argparse + +MODRM_MO0 = 0 +MODRM_MO1 = 1 +MODRM_MO2 = 2 +MODRM_MO3 = 3 + +#TODO: need to be based on the number test cases +SEGMENT_SIZE = 32768 +CODE_MEM_SIZE = 32768 + +TEST_PASS_CTR_VAR = "test_passed" +TEST_FAIL_CTR_VAR = "test_failed" +TEST_ERROR_CTR_VAR = "test_errors" + +class Instruction: + def __init__(self, name, opcode, modrm_reg, result_bytes, expected_val): + self.name = name + self.opcode = opcode + self.modrm_reg = modrm_reg + self.result_bytes = result_bytes + self.expected_val = expected_val + + +class Register: + def __init__(self, mnemonic, modrm_rm, name): + self.mnemonic = mnemonic + self.modrm_rm = modrm_rm + self.name = name + +class Segment: + def __init__(self, name, prefix, array): + self.name = name + self.prefix = prefix + self.array = array + + +BX_SI = Register(["%bx", "%si"], 0, ["bx", "si"]) +BX_DI = Register(["%bx", "%di"], 1, ["bx", "di"]) +BP_SI = Register(["%bp", "%si"], 2, ["bp", "si"]) +BP_DI = Register(["%bp", "%di"], 3, ["bp", "di"]) +SI = Register(["%si"], 4, ["si"]) +DI = Register(["%di"], 5, ["di"]) +BP = Register(["%bp"], 6, ["bp"]) +BX = Register(["%bx"], 7, ["bx"]) + +SMSW = Instruction("smsw", "0xf, 0x1", 4, 2, "expected_msw") +SLDT = Instruction("sldt", "0xf, 0x0", 0, 2, "expected_ldt") +STR = Instruction("str", "0xf, 0x0", 1, 2, "expected_tr") +SIDT = Instruction("sidt", "0xf, 0x1", 1, 6, "&expected_idt") +SGDT = Instruction("sgdt", "0xf, 0x1", 0, 6, "&expected_gdt") + +CS = Segment("cs", "", "code") +DS = Segment("ds", "", "data") +SS = Segment("ss", "", "stack") +ES = Segment("es", "0x26", "data_es") +FS = Segment("fs", "0x64", "data_fs") +GS = Segment("gs", "0x65", "data_gs") + +DATA_SEGS = [ DS, ES, FS, GS ] +INSTS = [SMSW, SLDT, STR, SGDT, SIDT ] + +MO0 = [ BX_SI, BX_DI, BP_SI, BP_DI, SI, DI, BX ] +MO1 = [ BX_SI, BX_DI, BP_SI, BP_DI, SI, DI, BP, BX ] +MO2 = [ BX_SI, BX_DI, BP_SI, BP_DI, SI, DI, BP, BX ] + + +def two_comp_8(val): + if (val > 0): + return val + else: + return ((abs(val) ^ 0xff) + 1) & 0xff + +def two_comp_16(val): + if (val > 0): + return val + else: + return ((abs(val) ^ 0xffff) + 1) & 0xffff + +def my_hex(val): + return hex(val).rstrip("L") + +def get_segment_prefix(segment, register, modrm): + """ default segments """ + if (segment.prefix == ""): + segment_str = "" + if (register == BX_SI): + segment_chk_str = "data" + elif (register == BX_DI): + segment_chk_str = "data" + elif (register == BP_SI): + segment_chk_str = "stack" + elif (register == BP_DI): + segment_chk_str = "stack" + elif (register == SI): + segment_chk_str = "data" + elif (register == DI): + segment_chk_str = "data" + elif (register == BP): + # This is for a pure disp32, no register involved. Thus, default is data + if ((modrm >> 6) == 0): + segment_chk_str = "data" + else: + segment_chk_str = "stack" + elif (register == BX): + segment_chk_str = "data" + else: # we should not fall here + segment_chk_str = "data" + else: + segment_str = segment.prefix + ", " + segment_chk_str = segment.array + + return segment_str, segment_chk_str + +def generate_check_code(comment, segment_chk_str, address, inst, pass_ctr, fail_ctr): + # TODO: Use an enum here + comment += ". " + if (inst.result_bytes == 2): + checkcode = "\tgot = *(unsigned short *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tpr_result(got, expected, \"" + comment + "\", " + pass_ctr + ", " + fail_ctr + ");\n" + elif (inst.result_bytes == 6): + checkcode = "\tgot = (struct table_desc *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tpr_result_table(got, expected, \"" + comment + "\", " + pass_ctr + ", " + fail_ctr + ");\n" + return checkcode + +def generate_disp(modrm, disp): + modrm_mod = modrm >> 6 + modrm_rm = modrm & 0x7 + if (modrm_mod == 0): + # if r/m is 6 (same as BP), this is a disp16 + if (modrm_rm == 6): + disp_2comp = two_comp_16(disp) + disp_str = ", " + str(my_hex(disp_2comp & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 8) & 0xff)) + else: + disp_str = "" + elif (modrm_mod == 1): + disp_2comp = two_comp_8(disp) + disp_str = ", " + str(my_hex(disp)) + elif (modrm_mod == 2): + disp_2comp = two_comp_16(disp) + disp_str = ", " + str(my_hex(disp_2comp & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 8) & 0xff)) + + return disp_str + +def generate_code(tc_nr, segment, inst, register, modrm_mod, index, disp): + code_start = "\t\".byte " + code_end = "\\n\\t\"\n" + + modrm = (modrm_mod << 6) | (inst.modrm_reg << 3) | register.modrm_rm + modrm_str = ", " + str(my_hex(modrm)) + + mov_reg_str = "" + for m in register.mnemonic: + val = two_comp_16(index/len(register.mnemonic)) + # we are just splitting the index between the number of registers indicated in modrm (max is 2) + # this should not be a problem as we always expect the index to be an even number + mov_reg_str += "\t\"mov $" + str(my_hex(val)) + ", " + m + "\\n\\t\"\n" + + segment_str, segment_chk_str = get_segment_prefix(segment, register, modrm) + + opcode_str = inst.opcode + + disp_str = generate_disp(modrm, disp) + + comment = "Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment_chk_str + "] " + comment += "INSN: " + inst.name + "(" + if (len(register.name) == 2): + comment += register.name[0] + " + " + register.name[1] + else: + comment += register.name[0] + if (modrm_mod == 0): + if ((modrm & 0x7) == 6): + comment += " + disp32). " + else: + comment += "). " + elif (modrm_mod == 1): + comment += " + disp8). " + elif (modrm_mod == 2): + comment += " + disp16). " + comment += "EFF_ADDR[" + str(my_hex(index + disp)) + "]. " + for n in register.name: + comment += n + "[" + str(my_hex(index/len(register.name))) + "] " + if (modrm_mod == 0): + comment += "" + elif ((modrm_mod == 0) and ((modrm & 0x7) == 6)): + comment += "disp16[" + str(my_hex(disp)) + "]" + elif (modrm_mod == 1): + comment += "disp8[" + str(my_hex(disp)) + "]" + elif (modrm_mod == 2): + comment += "disp16[" + str(my_hex(disp)) + "]" + + code = "\t/* " + comment + " */\n" + code += mov_reg_str + code += code_start + segment_str + opcode_str + modrm_str + disp_str + code_end + + checkcode = generate_check_code(comment, segment_chk_str, index + disp, inst, TEST_PASS_CTR_VAR, TEST_FAIL_CTR_VAR) + + return code, checkcode, inst.result_bytes + +def generate_special_unit_tests(start_tc_nr, segment, inst, start_idx): + code = "" + checkcode = "" + index = start_idx + tc_nr = start_tc_nr + code_start = "\t\".byte " + code_end = "\\n\\t\"\n" + opcode_str = inst.opcode + + # MOD = 0, r/m = 6 (BP), no index is used, only a disp16 + modrm = (MODRM_MO0 << 6) | (inst.modrm_reg << 3) | BP.modrm_rm + modrm_str = ", " + str(my_hex(modrm)) + + segment_str, segment_chk_str = get_segment_prefix(segment, BP, modrm) + + disp_str = generate_disp(modrm, index) + + comment = "Special Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment.name + "] " + comment += "INSN: " + inst.name + " (disp32)." + comment += "EFF_ADDR[" + str(my_hex(index)) + "]." + comment += " disp32[" + str(my_hex(index)) + "]" + + code = "\t/* " + comment + " */\n" + code += code_start + segment_str + opcode_str + modrm_str + disp_str + code_end + + checkcode += generate_check_code(comment, segment_chk_str, index, inst, TEST_PASS_CTR_VAR, TEST_FAIL_CTR_VAR) + + index += inst.result_bytes + tc_nr += 1 + + return code, checkcode, index, tc_nr + +def generate_unit_tests(segment, inst, start_idx, start_tc_nr): + code = "" + check_code = "" + index = start_idx + testcase_nr = start_tc_nr + + code += "\t /* ==================== Test code for " + inst.name + " ==================== */\n" + code += "\t\"test_umip_" + inst.name + "_" + segment.name + ":\\t\\n\"\n" + + check_code += "\n/* AUTOGENERATED CODE */\n" + if (inst.result_bytes == 2): + check_code += "static void check_tests_" + inst.name + "_" + segment.name + "(const unsigned short expected)\n" + check_code += "{\n" + check_code += "\tunsigned short got;\n\n" + elif (inst.result_bytes == 6): + check_code += "static void check_tests_" + inst.name + "_" + segment.name + "(const struct table_desc *expected)\n" + check_code += "{\n" + check_code += "\tstruct table_desc *got;\n\n" + + run_check_code = "\tcheck_tests_" + inst.name + "_" + segment.name + "(" + inst.expected_val + ");\n" + check_code += "\tprintf(\"=======Results for " + inst.name + " in segment " + segment.name + "=============\\n\");\n" + + for reg in MO0: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO0, index, 0) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + # force a negative displacement + start_addr = -100 + index += 100 + + for reg in MO1: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO1, index, start_addr) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + # force a negative index + start_addr += index + 100 + index = -100 + + for reg in MO2: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO2, index, start_addr) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + start_addr += index + + c, chk, idx, tc_nr = generate_special_unit_tests(testcase_nr, segment, inst, start_addr) + code += c + check_code += chk + testcase_nr = tc_nr + start_addr = idx + + code += "\t\"test_umip_" + inst.name + "_" + segment.name + "_end:\\t\\n\"\n" + check_code += "}\n\n" + + return code, check_code, run_check_code, start_addr, testcase_nr + +def generate_tests_all_insts(seg, start_index, start_test_nr): + run_check_code = "" + test_code = "" + check_code = "" + index = start_index + test_nr = start_test_nr + + for inst in INSTS: + tc, chkc, hdr, index, test_nr = generate_unit_tests(seg, inst, index, test_nr) + run_check_code += hdr + test_code += tc + check_code += chkc + + return test_code, check_code, run_check_code, index, test_nr + +def generate_test_cases(test_code, check_code): + index = 0 + + header_info = "/* ******************** AUTOGENERATED CODE ******************** */\n" + header_info += "#define SEGMENT_SIZE " + str(SEGMENT_SIZE) + "\n" + header_info += "#define CODE_MEM_SIZE " + str(CODE_MEM_SIZE) + "\n" + header_info += "\n" + header_info += "void check_results(void);\n" + header_info += "\n" + + check_code += "/* ******************** AUTOGENERATED CODE ******************** */\n" + check_code += "#include \n" + check_code += "#include \"test_umip_ldt_16.h\"\n\n" + check_code += "#include \"umip_test_defs.h\"\n\n" + check_code += "\n" + check_code +="int " + TEST_PASS_CTR_VAR + ";\n" + check_code +="int " + TEST_FAIL_CTR_VAR + ";\n" + check_code +="int " + TEST_ERROR_CTR_VAR + ";\n" + check_code += "\n" + check_code += "unsigned char data[SEGMENT_SIZE];\n" + check_code += "unsigned char data_es[SEGMENT_SIZE];\n" + check_code += "unsigned char data_fs[SEGMENT_SIZE];\n" + check_code += "unsigned char data_gs[SEGMENT_SIZE];\n" + check_code += "unsigned char stack_32[SEGMENT_SIZE];\n" + check_code += "unsigned char stack[SEGMENT_SIZE];\n" + check_code += "\n" + + run_check_code = "" + + test_code += "\tasm(\n" + test_code += "\t /* ******************** AUTOGENERATED CODE ******************** */\n" + test_code += "\t\".pushsection .rodata\\n\\t\"\n" + test_code += "\t\"test_umip:\\n\\t\"\n" + test_code += "\t\".code16\\n\\t\"\n" + test_code += "\t/* setup stack */\n" + test_code += "\t\"mov $" + str(SEGMENT_SIZE) + ", %sp\\n\\t\"\n" + test_code += "\t\"mov %si, %ss\\n\\t\"\n" + test_code += "\t/* save caller's cs */\n" + test_code += "\t\"push %dx\\n\\t\"\n" + test_code += "\t/* save caller's sp */\n" + test_code += "\t\"push %ax\\n\\t\"\n" + test_code += "\t/* save caller's ss */\n" + test_code += "\t\"push %bx\\n\\t\"\n" + + test_nr = 0 + + for seg in DATA_SEGS: + index = 0 + tc, chkc, rchk, index, test_nr = generate_tests_all_insts(seg, index, test_nr) + run_check_code += rchk + test_code += tc + check_code += chkc + + test_code += "\t/* preparing to return */\n" + test_code += "\t/* restore caller's ss */\n" + test_code += "\t\"pop %bx\\n\\t\"\n" + test_code += "\t/* restore caller's sp */\n" + test_code += "\t\"pop %ax\\n\\t\"\n" + test_code += "\t/*\n" + test_code += "\t * We only need the return IP, CS is already in stack\n" + test_code += "\t * jump to interim_start, which is at the beginning of\n" + test_code += "\t * this chunk of code\n" + test_code += "\t */\n" + test_code += "\t\"push $0\\n\\t\"\n" + test_code += "\t\"retf\\n\\t\"\n" + test_code += "\t\"test_umip_end:\\t\\n\"\n" + test_code += "\t\".code32\\n\\t\"\n" + test_code += "\t\".popsection\\n\\t\"\n" + test_code += "\t);\n" + + check_code += "\n" + check_code += "void check_results(void)\n" + check_code += "{\n" + check_code += run_check_code + check_code += "}\n" + check_code += "\n" + + return test_code, check_code, header_info, index + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--emulate-all", help="Test all UMIP-protected instructions. Otherwise, test code for STR and SLDT will not be generated", + action="store_true") + + args = parser.parse_args() + if args.emulate_all == False: + print ("Test code will not be generated for instructions SLDT and STR") + INSTS.remove(SLDT) + INSTS.remove(STR) + else: + print ("Generate test code for all UMIP-protected instructions") + +def write_test_files(): + parse_args() + + check_code = "" + test_code = "/* This is an autogenerated file. If you intend to debug, better to debug the generating script. */\n\n" + test_code += "\n" + test_code, check_code, check_code_hdr, global_index = generate_test_cases(test_code, check_code) + + fcheck_code = open("test_umip_ldt_16.c", "w") + fheader = open("test_umip_ldt_16.h", "w") + ftest_code = open("test_umip_code_16.h", "w") + ftest_code.writelines(test_code) + fheader.writelines(check_code_hdr) + fcheck_code.writelines(check_code) + ftest_code.close() + fcheck_code.close() + fheader.close() + +write_test_files() diff --git a/meta-luv/recipes-core/umip/files/umip_test_gen_32.py b/meta-luv/recipes-core/umip/files/umip_test_gen_32.py new file mode 100644 index 00000000000..e1bf7e9af17 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_gen_32.py @@ -0,0 +1,663 @@ +""" Test-case generator for UMIP +Copyright Intel Corporation 2017 + +This file generates opcdoes for all (well, most) of the combinations +of memory operands for the UMIP-protected instructions. This includes +all the ModRM values and segments. + +TODO: Add support for 16-bit address encodings +TODO: Add support for SiB address encodings""" + +import argparse + +MODRM_MO0 = 0 +MODRM_MO1 = 1 +MODRM_MO2 = 2 +MODRM_MO3 = 3 + +#TODO: need to be based on the number test cases +SEGMENT_SIZE = 262144 +CODE_MEM_SIZE = 262144 + +TEST_PASS_CTR_VAR = "test_passed" +TEST_FAIL_CTR_VAR = "test_failed" +TEST_ERROR_CTR_VAR = "test_errors" + + +class Instruction: + def __init__(self, name, opcode, modrm_reg, result_bytes, expected_val): + self.name = name + self.opcode = opcode + self.modrm_reg = modrm_reg + self.result_bytes = result_bytes + self.expected_val = expected_val + + +class Register: + def __init__(self, mnemonic, modrm_rm, name): + self.mnemonic = mnemonic + self.modrm_rm = modrm_rm + self.name = name + +class Segment: + def __init__(self, name, prefix, array): + self.name = name + self.prefix = prefix + self.array = array + + +EAX = Register("%eax", 0, "eax") +ECX = Register("%ecx", 1, "ecx") +EDX = Register("%edx", 2, "edx") +EBX = Register("%ebx", 3, "ebx") +ESP = Register("%esp", 4, "esp") +EBP = Register("%ebp", 5, "ebp") +ESI = Register("%esi", 6, "esi") +EDI = Register("%edi", 7, "edi") + +SMSW = Instruction("smsw", "0xf, 0x1", 4, 2, "expected_msw") +SLDT = Instruction("sldt", "0xf, 0x0", 0, 2, "expected_ldt") +STR = Instruction("str", "0xf, 0x0", 1, 2, "expected_tr") +SIDT = Instruction("sidt", "0xf, 0x1", 1, 6, "&expected_idt") +SGDT = Instruction("sgdt", "0xf, 0x1", 0, 6, "&expected_gdt") + +CS = Segment("cs", "", "code") +DS = Segment("ds", "", "data") +SS = Segment("ss", "", "stack") +ES = Segment("es", "0x26", "data_es") +FS = Segment("fs", "0x64", "data_fs") +GS = Segment("gs", "0x65", "data_gs") + +DATA_SEGS = [ DS, ES, FS, GS ] +INSTS = [SMSW, SLDT, STR, SGDT, SIDT ] + +MO0 = [ EAX, ECX, EDX, EBX, ESI, EDI ] +MO1 = [ EAX, ECX, EDX, EBX, EBP, ESI, EDI ] +MO2 = MO1 + +SIB_index = [ EAX, ECX, EDX, EBX, EBP, ESI, EDI ] + +SIB_base_MO0 = [ EAX, ECX, EDX, EBX, ESI, EDI ] +SIB_base_MO1 = [ EAX, ECX, EDX, EBX, EBP, ESI, EDI] +SIB_base_MO2 = SIB_base_MO1 + +def two_comp_32(val): + if (val > 0): + return val + else: + return ((abs(val) ^ 0xffffffff) + 1) & 0xffffffff + +def two_comp_8(val): + if (val > 0): + return val + else: + return ((abs(val) ^ 0xff) + 1) & 0xff + +def my_hex(val): + return hex(val).rstrip("L") + +def find_backup_reg(do_not_use): + regs = [ EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI] + for u in do_not_use: + regs.remove(u) + return regs[0] + +def get_segment_prefix(segment, register, modrm, sib=0): + """ default segments """ + if (segment.prefix == ""): + segment_str = "" + if ((register == EBP) or (register == ESP)): + # This is for a pure disp32, no register involved. Thus, default is data + if (((modrm >> 6) == 0) and (modrm & 0x7) == 5): + segment_chk_str = "data" + # If using a sib byte and the base is EBP, use DS as the base is ignored + elif (((modrm >> 6) == 0) and ((modrm & 0x7) == 4) and ((sib & 0x7) == 5)): + segment_chk_str = "data" + else: + segment_chk_str = "stack" + else: + segment_chk_str = "data" + else: + segment_str = segment.prefix + ", " + segment_chk_str = segment.array + + return segment_str, segment_chk_str + +def generate_check_code(comment, segment_chk_str, address, inst, pass_ctr, fail_ctr): + # TODO: Use an enum here + if (inst.result_bytes == 2): + checkcode = "\tgot = *(unsigned short *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tpr_result(got, expected, \"" + comment + "\", " + pass_ctr + ", " + fail_ctr + ");\n" + elif (inst.result_bytes == 6): + checkcode = "\tgot = (struct table_desc *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tpr_result_table(got, expected, \"" + comment + "\", " + pass_ctr + ", " + fail_ctr + ");\n" + return checkcode + +def generate_disp(modrm, disp, sib=0): + modrm_mod = modrm >> 6 + if (modrm_mod == 0): + + # if a sib byte is used, disp 32 is used + if (((sib &7) == 5) and (modrm & 7) == 4): + disp_2comp = two_comp_32(disp) + disp_str = ", " + str(disp_2comp & 0xff) + ", " + disp_str += str((disp_2comp >> 8) & 0xff) + ", " + disp_str += str((disp_2comp >> 16) & 0xff) + ", " + disp_str += str((disp_2comp >> 24) & 0xff) + else: + disp_str = "" + elif (modrm_mod == 1): + disp_2comp = two_comp_8(disp) + disp_str = ", " + str(disp_2comp) + elif (modrm_mod == 2): + disp_2comp = two_comp_32(disp) + disp_str = ", " + str(disp_2comp & 0xff) + ", " + disp_str += str((disp_2comp >> 8) & 0xff) + ", " + disp_str += str((disp_2comp >> 16) & 0xff) + ", " + disp_str += str((disp_2comp >> 24) & 0xff) + + return disp_str + +def generate_code(tc_nr, segment, inst, register, modrm_mod, index, disp): + code_start = "\t\".byte " + code_end = "\\n\\t\"\n" + + modrm = (modrm_mod << 6) | (inst.modrm_reg << 3) | register.modrm_rm + modrm_str = ", " + str(my_hex(modrm)) + mov_reg_str = "\t\"mov $" + str(my_hex(two_comp_32(index))) + ", " + register.mnemonic + "\\n\\t\"\n" + + segment_str, segment_chk_str = get_segment_prefix(segment, register, modrm) + + opcode_str = inst.opcode + + disp_str = generate_disp(modrm, disp) + + comment = "Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment_chk_str + "] " + comment += "INSN: " + inst.name + "(" + register.name + if (modrm_mod == 0): + comment += "). " + elif (modrm_mod == 1): + comment += " + disp8). " + elif (modrm_mod == 2): + comment += " + disp32). " + comment += "EFF_ADDR[" + str(my_hex(index + disp)) + "]. " + comment += register.name + "[" + str(my_hex(index)) + "] " + if (modrm_mod == 0): + comment += "" + elif (modrm_mod == 1): + comment += "disp8[" + str(my_hex(disp)) + "]" + elif (modrm_mod == 2): + comment += "disp32[" + str(my_hex(disp)) + "]" + + code = "\t/* " + comment + " */\n" + code += mov_reg_str + code += code_start + segment_str + opcode_str + modrm_str + disp_str + code_end + + checkcode = generate_check_code(comment, segment_chk_str, index + disp, inst, TEST_PASS_CTR_VAR, TEST_FAIL_CTR_VAR) + + return code, checkcode, inst.result_bytes + +def generate_code_sib(tc_nr, segment, inst, reg_base, reg_index, modrm_mod, sib_index, sib_base, sib_scale, disp, special=None): + code_start = "\t\".byte " + code_end = "\\n\\t\"\n" + + modrm = (modrm_mod << 6) | (inst.modrm_reg << 3) | ESP.modrm_rm + sib = (sib_scale << 6) | (reg_index.modrm_rm << 3) | reg_base.modrm_rm + modrm_str = ", " + str(my_hex(modrm)) + sib_str = ", " + str(my_hex(sib)) + mov_reg_str = "\t\"mov $" + str(my_hex(two_comp_32(sib_base))) + ", " + reg_base.mnemonic + "\\n\\t\"\n" + mov_reg_str += "\t\"mov $" + str(my_hex(two_comp_32(sib_index))) + ", " + reg_index.mnemonic + "\\n\\t\"\n" + + if ((reg_index == ESP) or (reg_base == ESP)): + backup_reg = find_backup_reg([reg_base, reg_index]) + backup_str = "\t\"mov " + ESP.mnemonic + ", " + backup_reg.mnemonic + "\\n\\t\"\n" + restore_str = "\t\"mov " + backup_reg.mnemonic + ", " + ESP.mnemonic + "\\n\\t\"\n" + else: + backup_str = "" + restore_str = "" + + segment_str, segment_chk_str = get_segment_prefix(segment, reg_base, modrm, sib) + + opcode_str = inst.opcode + + disp_str = generate_disp(modrm, disp, sib) + + if (special != None): + comment = special + " Test case " + str(tc_nr) + ": " + else: + comment = "Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment_chk_str + "] " + comment += "INSN: " + inst.name + " SIB(b:" + reg_base.name + " i:" + reg_index.name + " s:" + str(sib_scale) + if (modrm_mod == 0): + comment += "). " + elif (modrm_mod == 1): + comment += " + disp8). " + elif (modrm_mod == 2): + comment += " + disp32). " + + # ignore index value when computing effective address + calc_index = sib_index + calc_base = sib_base + if (reg_index == ESP): + calc_index = 0 + # ignore base + if ((reg_base == EBP) and (modrm_mod == 0)): + calc_base = 0 + + eff_addr = calc_base + calc_index*(1< 127): + disp = 0 + else: + disp = index + index = 0 + sib_base = index - 3*(1<> 8) & 0xff)) + ", " + disp_str += str(my_hex((index >> 16) & 0xff)) + ", " + disp_str += str(my_hex((index >> 24) & 0xff)) + + comment = "Special Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment.name + "] " + comment += "INSN: " + inst.name + " (disp32)." + comment += "EFF_ADDR[" + str(my_hex(index)) + "]." + comment += " disp32[" + str(my_hex(index)) + "]" + + code = "\t/* " + comment + " */\n" + code += code_start + segment_str + opcode_str + modrm_str + disp_str +code_end + + checkcode += generate_check_code(comment, segment_chk_str, index, inst, TEST_PASS_CTR_VAR, TEST_FAIL_CTR_VAR) + + index += inst.result_bytes + tc_nr += 1 + + # With SIB, index is ignored if such index is ESP. This also means + # that the scale is ignored + for reg_base in SIB_base_MO0: + c, chk , i = generate_code_sib(tc_nr, segment, inst, reg_base, ESP, MODRM_MO0, 0xffff, index, 3, 0, "Special") + index += i + code += c + checkcode += chk + tc_nr += 1 + + disp = 0 + for reg_base in SIB_base_MO1: + c, chk , i = generate_code_sib(tc_nr, segment, inst, reg_base, ESP, MODRM_MO1, 0xffff, index, 3, disp, "Special") + disp += i + code += c + checkcode += chk + tc_nr += 1 + + index = index + disp + disp = 0 + + for reg_base in SIB_base_MO2: + c, chk , i = generate_code_sib(tc_nr, segment, inst, reg_base, ESP, MODRM_MO2, 0xfff, index, 3, disp, "Special") + disp += i + code += c + checkcode += chk + tc_nr += 1 + + index += disp + + # with SIB and base register as EBP and mod = 0, the base register is ignored and a disp32 is used. The default register is DS + disp = 0 + for sib_scale in range (0,4): + new_index = (index >> sib_scale) << sib_scale + disp = index - new_index + new_index >>= sib_scale + for sib_index in SIB_base_MO0: + c, chk, i = generate_code_sib(tc_nr, segment, inst, EBP, sib_index, MODRM_MO0, new_index, 0xeeee, sib_scale, disp, "Special") + code += c + disp += i + checkcode += chk + tc_nr += 1 + + index += disp + + #with SIB, base as EBP and base as ESP, only disp32 is considered in the calculation + c, chk, i = generate_code_sib(tc_nr, segment, inst, EBP, ESP, MODRM_MO0, 0xbbbb, 0xcccc, 3, index, "Special") + code += c + disp += i + checkcode += chk + tc_nr += 1 + + index += i + + return code, checkcode, index, tc_nr + +def generate_unit_tests(segment, inst, start_idx, start_tc_nr): + code = "" + check_code = "" + index = start_idx + testcase_nr = start_tc_nr + + code += "\t /* ==================== Test code for " + inst.name + " ==================== */\n" + code += "\t\"test_umip_" + inst.name + "_" + segment.name + ":\\t\\n\"\n" + + check_code += "\n/* AUTOGENERATED CODE */\n" + if (inst.result_bytes == 2): + check_code += "static void check_tests_" + inst.name + "_" + segment.name + "(const unsigned short expected)\n" + check_code += "{\n" + check_code += "\tunsigned short got;\n\n" + elif (inst.result_bytes == 6): + check_code += "static void check_tests_" + inst.name + "_" + segment.name + "(const struct table_desc *expected)\n" + check_code += "{\n" + check_code += "\tstruct table_desc *got;\n\n" + + run_check_code = "\tcheck_tests_" + inst.name + "_" + segment.name + "(" + inst.expected_val + ");\n" + check_code += "\tprintf(\"=======Results for " + inst.name + " in segment " + segment.name + "=============\\n\");\n" + + for reg in MO0: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO0, index, 0) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + # in signed 8-bit displacements, the max value is 255. Thus, correct, by adding + # the remainder to index + start_addr = index + if (start_addr > 127): + remainder = start_addr -127 + index = remainder + start_addr = 127 + else: + index = 0 + + for reg in MO1: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO1, index, start_addr) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + start_addr += index + index = 0 + + # Force some indexes to be negative + start_addr += 127 + index -=127 + + for reg in MO2: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO2, index, start_addr) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + start_addr += index + + c, chk, start_addr, testcase_nr = generate_unit_tests_sib(segment, inst, start_addr, testcase_nr) + code += c + check_code += chk + + c, chk, idx, tc_nr = generate_special_unit_tests(testcase_nr, segment, inst, start_addr) + code += c + check_code += chk + testcase_nr = tc_nr + start_addr = idx + + code += "\t\"test_umip_" + inst.name + "_" + segment.name + "_end:\\t\\n\"\n" + check_code += "}\n\n" + + return code, check_code, run_check_code, start_addr, testcase_nr + +def generate_tests_all_insts(seg, start_index, start_test_nr): + run_check_code = "" + test_code = "" + check_code = "" + index = start_index + test_nr = start_test_nr + + for inst in INSTS: + tc, chkc, hdr, index, test_nr = generate_unit_tests(seg, inst, index, test_nr) + run_check_code += hdr + test_code += tc + check_code += chkc + + return test_code, check_code, run_check_code, index, test_nr + +def generate_test_cases(test_code, check_code): + header_info = "/* ******************** AUTOGENERATED CODE ******************** */\n" + header_info += "#define SEGMENT_SIZE " + str(SEGMENT_SIZE) + "\n" + header_info += "#define CODE_MEM_SIZE " + str(CODE_MEM_SIZE) + "\n" + header_info += "\n" + header_info += "void check_results(void);\n" + header_info += "\n" + + check_code += "/* ******************** AUTOGENERATED CODE ******************** */\n" + check_code += "#include \n" + check_code += "#include \"test_umip_ldt_32.h\"\n\n" + check_code += "#include \"umip_test_defs.h\"\n\n" + check_code += "\n" + check_code +="int " + TEST_PASS_CTR_VAR + ";\n" + check_code +="int " + TEST_FAIL_CTR_VAR + ";\n" + check_code +="int " + TEST_ERROR_CTR_VAR + ";\n" + check_code += "\n" + check_code += "unsigned char data[SEGMENT_SIZE];\n" + check_code += "unsigned char data_es[SEGMENT_SIZE];\n" + check_code += "unsigned char data_fs[SEGMENT_SIZE];\n" + check_code += "unsigned char data_gs[SEGMENT_SIZE];\n" + check_code += "unsigned char stack[SEGMENT_SIZE];\n" + check_code += "\n" + + run_check_code = "" + + test_code += "\tasm(\n" + test_code += "\t /* ******************** AUTOGENERATED CODE ******************** */\n" + test_code += "\t\".pushsection .rodata\\n\\t\"\n" + test_code += "\t\"test_umip:\\t\\n\"\n" + test_code += "\t/* setup stack */\n" + test_code += "\t\"mov $" + str(SEGMENT_SIZE) + ", %esp\\n\\t\"\n" + test_code += "\t\"mov %ecx, %ss\\n\\t\"\n" + test_code += "\t/* save old cs as passed by us before retf'ing here */\n" + test_code += "\t\"push %edx\\n\\t\"\n" + test_code += "\t/* save old esp as passed by us before retf'ing here */\n" + test_code += "\t\"push %eax\\n\\t\"\n" + test_code += "\t/* save old ss as passed by us before retf'ing here */\n" + test_code += "\t\"push %ebx\\n\\t\"\n" + + + test_nr = 0 + + for seg in DATA_SEGS: + index = 0 + tc, chkc, rchk, index, test_nr = generate_tests_all_insts(seg, index, test_nr) + run_check_code += rchk + test_code += tc + check_code += chkc + + test_code += "\t/* preparing to return */\n" + test_code += "\t/* restore ss */\n" + test_code += "\t\"pop %ebx\\n\\t\"\n" + test_code += "\t/* restore esp */\n" + test_code += "\t\"pop %eax\\n\\t\"\n" + test_code += "\t/* setting return IP, CS is already in stack */\n" + test_code += "\t\"push $finish_testing\\n\\t\"\n" + test_code += "\t\"retf\\n\\t\"\n" + test_code += "\t\"test_umip_end:\\t\\n\"\n" + test_code += "\t\".popsection\\n\\t\"\n" + test_code += "\t);\n" + + check_code += "\n" + check_code += "void check_results(void)\n" + check_code += "{\n" + check_code += run_check_code + check_code += "}\n" + check_code += "\n" + + return test_code, check_code, header_info, index + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--emulate-all", help="Test all UMIP-protected instructions. Otherwise, test code for STR and SLDT will not be generated.", + action="store_true") + + args = parser.parse_args() + if args.emulate_all == False: + print ("Test code will not be generated for instructions SLDT and STR") + INSTS.remove(SLDT) + INSTS.remove(STR) + else: + print ("Generate test code for all UMIP-protected instructions") + +def write_test_files(): + parse_args() + + check_code = "" + test_code = "/* This is an autogenerated file. If you intend to debug, better to debug the generating script. */\n\n" + test_code += "\n" + test_code, check_code, check_code_hdr, global_index = generate_test_cases(test_code, check_code) + + fcheck_code = open("test_umip_ldt_32.c", "w") + fheader = open("test_umip_ldt_32.h", "w") + ftest_code = open("test_umip_code_32.h", "w") + ftest_code.writelines(test_code) + fheader.writelines(check_code_hdr) + fcheck_code.writelines(check_code) + ftest_code.close() + fcheck_code.close() + fheader.close() + +write_test_files() diff --git a/meta-luv/recipes-core/umip/files/umip_test_gen_64.py b/meta-luv/recipes-core/umip/files/umip_test_gen_64.py new file mode 100644 index 00000000000..11d5588546b --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_gen_64.py @@ -0,0 +1,673 @@ +""" Test-case generator for UMIP +Copyright Intel Corporation 2017 + +This file generates opcdoes for all (well, most) of the combinations +of memory operands for the UMIP-protected instructions. This includes +all the ModRM values and segments. + +TODO: Add support for 16-bit address encodings +TODO: Add support for SiB address encodings""" + +import argparse + +MODRM_MO0 = 0 +MODRM_MO1 = 1 +MODRM_MO2 = 2 +MODRM_MO3 = 3 + +#TODO: need to be based on the number test cases +SEGMENT_SIZE = 1048576 +CODE_MEM_SIZE = 1048576 + +TEST_PASS_CTR_VAR = "test_passed" +TEST_FAIL_CTR_VAR = "test_failed" +TEST_ERROR_CTR_VAR = "test_errors" + +class Instruction: + def __init__(self, name, opcode, modrm_reg, result_bytes, expected_val): + self.name = name + self.opcode = opcode + self.modrm_reg = modrm_reg + self.result_bytes = result_bytes + self.expected_val = expected_val + + +class Register: + def __init__(self, mnemonic, modrm_rm, name, rex_x, rex_b): + self.mnemonic = mnemonic + self.modrm_rm = modrm_rm + self.name = name + self.rex_x = rex_x + self.rex_b = rex_b + +class Segment: + def __init__(self, name, prefix, array): + self.name = name + self.prefix = prefix + self.array = array + + +RAX = Register("%rax", 0, "rax", 0, 0) +RCX = Register("%rcx", 1, "rcx", 0, 0) +RDX = Register("%rdx", 2, "rdx", 0, 0) +RBX = Register("%rbx", 3, "rbx", 0, 0) +RSP = Register("%rsp", 4, "rsp", 0, 0) +RBP = Register("%rbp", 5, "rbp", 0, 0) +RSI = Register("%rsi", 6, "rsi", 0, 0) +RDI = Register("%rdi", 7, "rdi", 0, 0) +R8 = Register("%r8", 0, "r8", 0x42, 0x41) +R9 = Register("%r9", 1, "r9", 0x42, 0x41) +R10 = Register("%r10", 2, "r10", 0x42, 0x41) +R11 = Register("%r11", 3, "r11", 0x42, 0x41) +R12 = Register("%r12", 4, "r12", 0x42, 0x41) +R13 = Register("%r13", 5, "r13", 0x42, 0x41) +R14 = Register("%r14", 6, "r14", 0x42, 0x41) +R15 = Register("%r15", 7, "r15", 0x42, 0x41) + + +SMSW = Instruction("smsw", "0xf, 0x1", 4, 2, "expected_msw") +SLDT = Instruction("sldt", "0xf, 0x0", 0, 2, "expected_ldt") +STR = Instruction("str", "0xf, 0x0", 1, 2, "expected_tr") +SIDT = Instruction("sidt", "0xf, 0x1", 1, 6, "&expected_idt") +SGDT = Instruction("sgdt", "0xf, 0x1", 0, 6, "&expected_gdt") + +CS = Segment("cs", "", "code") +DS = Segment("ds", "", "data") +SS = Segment("ss", "", "stack") +ES = Segment("es", "0x26", "data_es") +FS = Segment("fs", "0x64", "data_fs") +GS = Segment("gs", "0x65", "data_gs") + +DATA_SEGS = [ FS, GS ] +INSTS = [SMSW, SLDT, STR, SGDT, SIDT ] + +MO0 = [ RAX, RCX, RDX, RBX, RSI, RDI, R8, R9, R10, R11, R14, R15 ] +MO1 = [ RAX, RCX, RDX, RBX, RBP, RSI, RDI, R8, R9, R10, R11, R13, R14, R15 ] +MO2 = MO1 + +SIB_index = [ RAX, RCX, RDX, RBX, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15 ] +SIB_base_MO0 = [ RAX, RCX, RDX, RBX, RSI, RDI, R8, R9, R10, R11, R12, R14, R15 ] +SIB_base_MO1 = [ RAX, RCX, RDX, RBX, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15 ] +SIB_base_MO2 = SIB_base_MO1 + +def two_comp_32(val): + if (val >= 0): + return val + else: + return ((abs(val) ^ 0xffffffff) + 1) & 0xffffffff + +def two_comp_64(val): + if (val >= 0): + return val + else: + return ((abs(val) ^ 0xffffffffffffffff) + 1) & 0xffffffffffffffff + +def two_comp_8(val): + if (val >= 0): + return val + else: + return ((abs(val) ^ 0xff) + 1) & 0xff + +def my_hex(val): + return hex(val).rstrip("L") + +def find_backup_reg(do_not_use): + regs = [ RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15] + for u in do_not_use: + regs.remove(u) + return regs[0] + +def get_segment_prefix(segment, register, modrm, sib=0): + """ default segments """ + if (segment.prefix == ""): + segment_str = "" + if ((register == RBP) or (register == RSP)): + # This is for a pure disp32, no register involved. Thus, default is data + if (((modrm >> 6) == 0) and (modrm & 0x7) == 5): + segment_chk_str = "data" + # If using a sib byte and the base is RBP, use DS as the base is ignored + elif (((modrm >> 6) == 0) and ((modrm & 0x7) == 4) and ((sib & 0x7) == 5)): + segment_chk_str = "data" + else: + segment_chk_str = "stack" + else: + segment_chk_str = "data" + else: + segment_str = segment.prefix + ", " + segment_chk_str = segment.array + + return segment_str, segment_chk_str + +def generate_check_code(comment, segment_chk_str, address, inst, pass_ctr, fail_ctr): + # TODO: Use an enum here + if (inst.result_bytes == 2): + checkcode = "\tgot = *(unsigned short *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tpr_result(got, expected, \"" + comment + "\", " + pass_ctr + ", " + fail_ctr + ");\n" + elif (inst.result_bytes == 6): + checkcode = "\tgot = (struct table_desc *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tpr_result_table(got, expected, \"" + comment + "\", " + pass_ctr + ", " + fail_ctr + ");\n" + return checkcode + +def generate_disp(modrm, disp, sib=0): + modrm_mod = modrm >> 6 + if (modrm_mod == 0): + + # if a sib byte is used, disp 32 is used + if (((sib &7) == 5) and (modrm & 7) == 4): + disp_2comp = two_comp_32(disp) + disp_str = ", " + str(my_hex(disp_2comp & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 8) & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 16) & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 24) & 0xff)) + else: + disp_str = "" + elif (modrm_mod == 1): + disp_2comp = two_comp_8(disp) + disp_str = ", " + str(my_hex(disp_2comp)) + elif (modrm_mod == 2): + disp_2comp = two_comp_32(disp) + disp_str = ", " + str(my_hex(disp_2comp & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 8) & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 16) & 0xff)) + ", " + disp_str += str(my_hex((disp_2comp >> 24) & 0xff)) + + return disp_str + +def generate_code(tc_nr, segment, inst, register, modrm_mod, index, disp): + code_start = "\t\".byte " + code_end = "\\n\\t\"\n" + + modrm = (modrm_mod << 6) | (inst.modrm_reg << 3) | register.modrm_rm + modrm_str = ", " + str(my_hex(modrm)) + mov_reg_str = "\t\"mov $" + str(my_hex(two_comp_64(index))) + ", " + register.mnemonic + "\\n\\t\"\n" + + segment_str, segment_chk_str = get_segment_prefix(segment, register, modrm) + + opcode_str = inst.opcode + + if (register.rex_b != 0): + rex_b_str = my_hex(register.rex_b) + ", " + else: + rex_b_str = "" + + disp_str = generate_disp(modrm, disp) + + comment = "Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment_chk_str + "] " + comment += "INSN: " + inst.name + "(" + register.name + if (modrm_mod == 0): + comment += "). " + elif (modrm_mod == 1): + comment += " + disp8). " + elif (modrm_mod == 2): + comment += " + disp32). " + comment += "EFF_ADDR[" + str(my_hex(index + disp)) + "]. " + comment += register.name + "[" + str(my_hex(index)) + "] " + if (modrm_mod == 0): + comment += "" + elif (modrm_mod == 1): + comment += "disp8[" + str(my_hex(disp)) + "]" + elif (modrm_mod == 2): + comment += "disp32[" + str(my_hex(disp)) + "]" + + code = "\t/* " + comment + " */\n" + code += mov_reg_str + code += code_start + segment_str + rex_b_str + opcode_str + modrm_str + disp_str + code_end + + checkcode = generate_check_code(comment, segment_chk_str, index + disp, inst, TEST_PASS_CTR_VAR, TEST_FAIL_CTR_VAR) + + return code, checkcode, inst.result_bytes + +def generate_code_sib(tc_nr, segment, inst, reg_base, reg_index, modrm_mod, sib_index, sib_base, sib_scale, disp, special=None): + code_start = "\t\".byte " + code_end = "\\n\\t\"\n" + + modrm = (modrm_mod << 6) | (inst.modrm_reg << 3) | RSP.modrm_rm + sib = (sib_scale << 6) | (reg_index.modrm_rm << 3) | reg_base.modrm_rm + modrm_str = ", " + str(my_hex(modrm)) + sib_str = ", " + str(my_hex(sib)) + mov_reg_str = "\t\"mov $" + str(my_hex(two_comp_64(sib_base))) + ", " + reg_base.mnemonic + "\\n\\t\"\n" + mov_reg_str += "\t\"mov $" + str(my_hex(two_comp_64(sib_index))) + ", " + reg_index.mnemonic + "\\n\\t\"\n" + + if ((reg_index == RSP) or (reg_base == RSP)): + backup_reg = find_backup_reg([reg_base, reg_index]) + backup_str = "\t\"mov " + RSP.mnemonic + ", " + backup_reg.mnemonic + "\\n\\t\"\n" + restore_str = "\t\"mov " + backup_reg.mnemonic + ", " + RSP.mnemonic + "\\n\\t\"\n" + else: + backup_str = "" + restore_str = "" + + segment_str, segment_chk_str = get_segment_prefix(segment, reg_base, modrm, sib) + + opcode_str = inst.opcode + + if ((reg_index.rex_x != 0) or (reg_base.rex_b != 0)): + rex_b_str = my_hex(reg_index.rex_x | reg_base.rex_b) + ", " + else: + rex_b_str = "" + + disp_str = generate_disp(modrm, disp, sib) + + if (special != None): + comment = special + " Test case " + str(tc_nr) + ": " + else: + comment = "Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment_chk_str + "] " + comment += "INSN: " + inst.name + " SIB(b:" + reg_base.name + " i:" + reg_index.name + " s:" + str(sib_scale) + if (modrm_mod == 0): + comment += "). " + elif (modrm_mod == 1): + comment += " + disp8). " + elif (modrm_mod == 2): + comment += " + disp32). " + + # ignore index value when computing effective address + calc_index = sib_index + calc_base = sib_base + if (reg_index == RSP): + calc_index = 0 + # ignore base + if ((reg_base == RBP) and (modrm_mod == 0)): + calc_base = 0 + + eff_addr = calc_base + calc_index*(1< 127): + disp = 0 + else: + disp = index + index = 0 + sib_base = index - 3*(1<> 8) & 0xff)) + ", " + disp_str += str(my_hex((index >> 16) & 0xff)) + ", " + disp_str += str(my_hex((index >> 24) & 0xff)) + + comment = "Ricardin Special Test case " + str(tc_nr) + ": " + comment += "SEG[" + segment.name + "] " + comment += "INSN: " + inst.name + " (disp32)." + comment += "EFF_ADDR[" + str(my_hex(index)) + "]." + comment += " disp32[" + str(my_hex(index)) + "]" + + code = "\t/* " + comment + " */\n" + code += "\t\"jmp 1f:\\n\\t\"\n" + code += "\t\"1f:\\n\\t\"\n" + code += code_start + segment_str + opcode_str + modrm_str + disp_str +code_end + + checkcode += generate_check_code(comment, segment_chk_str, index, inst, TEST_PASS_CTR_VAR, TEST_FAIL_CTR_VAR) + + index += inst.result_bytes + tc_nr += 1 + + # With SIB, index is ignored if such index is RSP. This also means + # that the scale is ignored + for reg_base in SIB_base_MO0: + c, chk , i = generate_code_sib(tc_nr, segment, inst, reg_base, RSP, MODRM_MO0, 0xffff, index, 3, 0, "Special") + index += i + code += c + checkcode += chk + tc_nr += 1 + + disp = 0 + for reg_base in SIB_base_MO1: + c, chk , i = generate_code_sib(tc_nr, segment, inst, reg_base, RSP, MODRM_MO1, 0xffff, index, 3, disp, "Special") + disp += i + code += c + checkcode += chk + tc_nr += 1 + + index = index + disp + disp = 0 + + for reg_base in SIB_base_MO2: + c, chk , i = generate_code_sib(tc_nr, segment, inst, reg_base, RSP, MODRM_MO2, 0xfff, index, 3, disp, "Special") + disp += i + code += c + checkcode += chk + tc_nr += 1 + + index += disp + + # with SIB and base register as RBP and mod = 0, the base register is ignored and a disp32 is used. The default register is DS + disp = 0 + for sib_scale in range (0,4): + new_index = (index >> sib_scale) << sib_scale + disp = index - new_index + new_index >>= sib_scale + for sib_index in SIB_base_MO0: + c, chk, i = generate_code_sib(tc_nr, segment, inst, RBP, sib_index, MODRM_MO0, new_index, 0xeeee, sib_scale, disp, "Special") + code += c + disp += i + checkcode += chk + tc_nr += 1 + + index += disp + + # with SIB, base as RBP and base as RSP, only disp32 is considered in the calculation + # in 64-bit, the disp is added to RIP + c, chk, i = generate_code_sib(tc_nr, segment, inst, RBP, RSP, MODRM_MO0, 0xbbbb, 0xcccc, 3, index, "Special") + code += c + disp += i + checkcode += chk + tc_nr += 1 + + index += i + + return code, checkcode, index, tc_nr + +def generate_unit_tests(segment, inst, start_idx, start_tc_nr): + code = "" + check_code = "" + index = start_idx + testcase_nr = start_tc_nr + + code += "\t /* ==================== Test code for " + inst.name + " ==================== */\n" + code += "\t\"test_umip_" + inst.name + "_" + segment.name + ":\\t\\n\"\n" + + check_code += "\n/* AUTOGENERATED CODE */\n" + if (inst.result_bytes == 2): + check_code += "static void check_tests_" + inst.name + "_" + segment.name + "(const unsigned short expected)\n" + check_code += "{\n" + check_code += "\tunsigned short got;\n\n" + elif (inst.result_bytes == 6): + check_code += "static void check_tests_" + inst.name + "_" + segment.name + "(const struct table_desc *expected)\n" + check_code += "{\n" + check_code += "\tstruct table_desc *got;\n\n" + + run_check_code = "\tcheck_tests_" + inst.name + "_" + segment.name + "(" + inst.expected_val + ");\n" + check_code += "\tprintf(\"=======Results for " + inst.name + " in segment " + segment.name + "=============\\n\");\n" + + for reg in MO0: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO0, index, 0) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + # in signed 8-bit displacements, the max value is 255. Thus, correct, by adding + # the remainder to index + start_addr = index + if (start_addr > 127): + remainder = start_addr -127 + index = remainder + start_addr = 127 + else: + index = 0 + + for reg in MO1: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO1, index, start_addr) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + start_addr += index + index = 0 + + # Force some indexes to be negative + start_addr += 127 + index -=127 + + for reg in MO2: + c, chk, idx = generate_code(testcase_nr, segment, inst, reg, MODRM_MO2, index, start_addr) + code += c + check_code += chk + index += idx + testcase_nr += 1 + + start_addr += index + + c, chk, start_addr, testcase_nr = generate_unit_tests_sib(segment, inst, start_addr, testcase_nr) + code += c + check_code += chk + + c, chk, idx, tc_nr = generate_special_unit_tests(testcase_nr, segment, inst, start_addr) + code += c + check_code += chk + testcase_nr = tc_nr + start_addr = idx + + code += "\t\"test_umip_" + inst.name + "_" + segment.name + "_end:\\t\\n\"\n" + check_code += "}\n\n" + + return code, check_code, run_check_code, start_addr, testcase_nr + +def generate_tests_all_insts(seg, start_index, start_test_nr): + run_check_code = "" + test_code = "" + check_code = "" + index = start_index + test_nr = start_test_nr + + for inst in INSTS: + tc, chkc, hdr, index, test_nr = generate_unit_tests(seg, inst, index, test_nr) + run_check_code += hdr + test_code += tc + check_code += chkc + + return test_code, check_code, run_check_code, index, test_nr + +def generate_test_cases(test_code, check_code): + header_info = "/* ******************** AUTOGENERATED CODE ******************** */\n" + header_info += "\n" + header_info += "#define SEGMENT_SIZE " + str(SEGMENT_SIZE) + "\n" + header_info += "#define CODE_MEM_SIZE " + str(CODE_MEM_SIZE) + "\n" + header_info += "void check_results(void);\n" + header_info += "\n" + + check_code += "/* ******************** AUTOGENERATED CODE ******************** */\n" + check_code += "#include \n" + check_code += "#include \"test_umip_ldt_64.h\"\n\n" + check_code += "#include \"umip_test_defs.h\"\n\n" + check_code += "\n" + check_code +="int " + TEST_PASS_CTR_VAR + ";\n" + check_code +="int " + TEST_FAIL_CTR_VAR + ";\n" + check_code +="int " + TEST_ERROR_CTR_VAR + ";\n" + check_code += "\n" + check_code += "unsigned char data_fs[SEGMENT_SIZE];\n" + check_code += "unsigned char data_gs[SEGMENT_SIZE];\n" + check_code += "\n" + run_check_code = "" + + test_code += "\tasm(\n" + test_code += "\t /* ******************** AUTOGENERATED CODE ******************** */\n" + test_code += "\t\".pushsection .rodata\\n\\t\"\n" + test_code += "\t\"test_umip:\\t\\n\"\n" + + + test_nr = 0 + + index = 0 + for seg in DATA_SEGS: + index = 0 + tc, chkc, rchk, index, test_nr = generate_tests_all_insts(seg, index, test_nr) + run_check_code += rchk + test_code += tc + check_code += chkc + + #test_code += "\t\"jmp $finish_testing\\n\\t\"\n" + test_code += "\t\"ret\\n\\t\"\n" + test_code += "\t\"test_umip_end:\\t\\n\"\n" + test_code += "\t\".popsection\\n\\t\"\n" + test_code += "\t);\n" + + check_code += "\n" + check_code += "void check_results(void)\n" + check_code += "{\n" + check_code += run_check_code + check_code += "}\n" + check_code += "\n" + + return test_code, check_code, header_info, index + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--emulate-all", help="Test all UMIP-protected instructions. Otherwise, test code for STR and SLDT will not be generated.", + action="store_true") + + args = parser.parse_args() + if args.emulate_all == False: + print ("Test code will not be generated for instructions SLDT and STR") + INSTS.remove(SLDT) + INSTS.remove(STR) + else: + print ("Generate test code for all UMIP-protected instructions") + +def write_test_files(): + parse_args() + + check_code = "" + test_code = "/* This is an autogenerated file. If you intend to debug, better to debug the generating script. */\n\n" + test_code += "\n" + test_code, check_code, check_code_hdr, global_index = generate_test_cases(test_code, check_code) + + fcheck_code = open("test_umip_ldt_64.c", "w") + fheader = open("test_umip_ldt_64.h", "w") + ftest_code = open("test_umip_code_64.h", "w") + ftest_code.writelines(test_code) + fheader.writelines(check_code_hdr) + fcheck_code.writelines(check_code) + ftest_code.close() + fcheck_code.close() + fheader.close() + +write_test_files() diff --git a/meta-luv/recipes-core/umip/files/umip_test_opnds.c b/meta-luv/recipes-core/umip/files/umip_test_opnds.c new file mode 100644 index 00000000000..70d006efcb6 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_opnds.c @@ -0,0 +1,519 @@ +#include +#include +#include +#include +#include "umip_test_defs.h" + +/* Register operands */ + +#if __x86_64__ +#define PUSH(reg) "push %%r"reg"\n" +#define POP(reg) "pop %%r"reg"\n" +#define SAVE_SP(reg) "mov %%rsp, %%r"reg"\n" +#define RESTORE_SP(reg) "mov %%r"reg", %%rsp\n" +#define PFX_ZEROS "16" +#else +#define PUSH(reg) "push %%e"reg"\n" +#define POP(reg) "pop %%e"reg"\n" +#define SAVE_SP(reg) "mov %%esp, %%e"reg"\n" +#define RESTORE_SP(reg) "mov %%e"reg", %%esp\n" +#define PFX_ZEROS "8" +#endif + +#define INSNreg16(insn, reg, scratch, scratch_sp) \ + /* + * Move initialization value to %scratch. Do it before changing %rsp as \ + * some compilers refer local variables as an offset from %esp. This \ + * code causes %scratch to be clobbered. This is OK as long it is not \ + * used in the caller function. \ + */ \ + "mov %0, %%"scratch"\n" \ + /* Make a backup of test register */ \ + PUSH(reg) \ + /* Write our initialization value in test register */ \ + "mov %%"scratch", %%"reg"\n" \ + /* In case we are testing %esp, make a backup to restore after test */ \ + SAVE_SP(scratch_sp) \ + /* Run our test: register operands */ \ + insn" %%"reg"\n" \ + NOP_SLED \ + /* Save result to scratch */ \ + "mov %%"reg", %%"scratch"\n" \ + /* Restore %esp */ \ + RESTORE_SP(scratch_sp) \ + /* Restore test register */ \ + POP(reg) \ + /* \ + * Since some compilers refer local variables as an offset from %esp, \ + * the test result can only be saved to a local variable only once %esp \ + * has been restored by an equal number of stack pops and pushes. \ + */ \ + "mov %%"scratch", %1\n" + +#define INSNreg32(insn, reg, scratch, scratch_sp) \ + /* + * Move initialization value to %scratch. Do it before changing %rsp as \ + * some compilers refer local variables as an offset from %esp. This \ + * code causes %scratch to be clobbered. This is OK as long it is not \ + * used in the caller function. \ + */ \ + "mov %0, %%e"scratch"\n" \ + /* Make a backup of test register */ \ + PUSH(reg) \ + /* Write our initialization value in test register */ \ + "mov %%e"scratch", %%e"reg"\n" \ + /* In case we are testing %esp, make a backup to restore after test */ \ + SAVE_SP(scratch_sp) \ + /* Run our test: register operands */ \ + insn" %%e"reg"\n" \ + NOP_SLED \ + /* Save result to scratch */ \ + "mov %%e"reg", %%e"scratch"\n" \ + /* Restore %esp */ \ + RESTORE_SP(scratch_sp) \ + /* Restore test register */ \ + POP(reg) \ + /* \ + * Since some compilers refer local variables as an offset from %esp, \ + * the test result can only be saved to a local variable only once %esp \ + * has been restored by an equal number of stack pops and pushes. \ + */ \ + "mov %%e"scratch", %1\n" + +#define INSNreg64(insn, reg, scratch, scratch_sp) \ + /* + * Move initialization value to %scratch. Do it before changing %rsp as \ + * some compilers refer local variables as an offset from %esp. This \ + * code causes %scratch to be clobbered. This is OK as long it is not \ + * used in the caller function. \ + */ \ + "mov %0, %%"scratch"\n" \ + /* Make a backup of test register */ \ + "push %%"reg"\n" \ + /* Write our initialization value in test register */ \ + "mov %%"scratch", %%"reg"\n" \ + /* In case we are testing %esp, make a backup to restore after test */ \ + "mov %%rsp, %%"scratch_sp"\n" \ + /* Run our test: register operands */ \ + insn" %%"reg"\n" \ + NOP_SLED \ + /* Save result to scratch */ \ + "mov %%"reg", %%"scratch"\n" \ + /* Restore %rsp */ \ + "mov %%"scratch_sp", %%rsp\n" \ + /* Restore test register */ \ + "pop %%"reg"\n" \ + /* \ + * Since some compilers refer local variables as an offset from %rsp, \ + * the test result can only be saved to a local variable only once %rsp \ + * has been restored by an equal number of stack pops and pushes. \ + */ \ + "mov %%"scratch", %1\n" + +#define CHECK_INSN(op_size, insn, reg, val, scratch, scratch_sp, init, exp) \ + do { \ + val = init; \ + mask = get_mask(op_size); \ + if (!mask) \ + return -1; \ + \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + asm volatile(INSNreg##op_size(insn, reg, scratch, scratch_sp) : "=m" (val) : "m" (val): "%"scratch, "%"scratch_sp ); \ + \ + if(inspect_signal(exp_signum, exp_sigcode)) \ + break; \ + /* \ + * Check that the bits that are supposed to change does so \ + * as well as that the bits that are not supposed to change \ + * does not change. \ + */ \ + if (((val & mask) == (exp & mask)) && ((exp & ~mask) == (exp & ~mask))) \ + pr_pass(test_passed, " On %s-bit '%s %s'! " \ + "Got [0x%0"PFX_ZEROS"lx] " \ + "Exp[0x%0"PFX_ZEROS"lx]\n", \ + #op_size, insn, reg, val, (exp&mask) | (init&~mask)); \ + else { \ + pr_fail(test_failed, " On %s-bit '%s %s'! " \ + "Got[0x%0"PFX_ZEROS"lx] " \ + "Exp[0x%0"PFX_ZEROS"lx]\n", \ + #op_size, insn, reg, val, (exp&mask) | (init&~mask)); \ + } \ + } while(0); + +#define CHECK_ALLreg32(insn, val, init, exp) \ + CHECK_INSN(16, insn, "ax", val, "cx", "dx", init, exp); \ + CHECK_INSN(16, insn, "cx", val, "ax", "dx", init, exp); \ + CHECK_INSN(16, insn, "dx", val, "ax", "cx", init, exp); \ + CHECK_INSN(16, insn, "bx", val, "ax", "dx", init, exp); \ + CHECK_INSN(16, insn, "bp", val, "ax", "dx", init, exp); \ + CHECK_INSN(16, insn, "si", val, "ax", "dx", init, exp); \ + CHECK_INSN(16, insn, "di", val, "ax", "dx", init, exp); \ + CHECK_INSN(32, insn, "ax", val, "cx", "dx", init, exp); \ + CHECK_INSN(32, insn, "cx", val, "ax", "dx", init, exp); \ + CHECK_INSN(32, insn, "dx", val, "ax", "cx", init ,exp); \ + CHECK_INSN(32, insn, "bx", val, "ax", "dx", init ,exp); \ + CHECK_INSN(32, insn, "bp", val, "ax", "dx", init, exp); \ + CHECK_INSN(32, insn, "si", val, "ax", "dx", init, exp); \ + CHECK_INSN(32, insn, "di", val, "ax", "dx", init, exp); + +#define CHECK_ALLreg64(insn, val, init, exp) \ + CHECK_INSN(64, insn, "rax", val, "rcx", "rdx", init, exp); \ + CHECK_INSN(64, insn, "rcx", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "rdx", val, "rax", "rcx", init, exp); \ + CHECK_INSN(64, insn, "rbx", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "rbp", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "rsi", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "rdi", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r8", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r9", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r10", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r11", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r12", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r13", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r14", val, "rax", "rdx", init, exp); \ + CHECK_INSN(64, insn, "r15", val, "rax", "rdx", init, exp); + +#if __x86_64__ +#define CHECK_ALLreg(insn, val, init, exp) \ + CHECK_ALLreg32(insn, val, init, exp) \ + CHECK_ALLreg64(insn, val, init, exp) +#else +#define CHECK_ALLreg(insn, val, init, exp) \ + CHECK_ALLreg32(insn, val, init, exp) +#endif + + +/* Memory operands */ +#if __x86_64__ +#define INSNmem(insn, reg, scratch, disp) \ + /* + * Move initialization value to %scratch. Do it before changing %rsp as \ + * some compilers refer local variables as an offset from %esp. This \ + * code causes %scratch to be clobbered. This is OK as long it is not \ + * used in the caller function. \ + */ \ + "mov %0, %%"scratch"\n" \ + /* \ + * Make a backup of our scratch memory. Adjust wrt %rsp according to the\ + * two stack pushes below. \ + */ \ + "push ("disp"-0x8-0x8)(%%rsp)\n" \ + /* Make a backup of contents of test register */ \ + "push %%"reg"\n" \ + /* Write our initialization value in scratch memory. */ \ + "mov %%"scratch", "disp"(%%rsp)\n" \ + /* Make test register point to our scratch memory. */ \ + "mov %%rsp, %%"reg"\n" \ + /* Run our test: register-indirect addressing with an offset. */ \ + insn" "disp"(%%"reg")\n" \ + NOP_SLED \ + /* Save result to %rax */ \ + "mov "disp"(%%rsp), %%"scratch"\n" \ + /* Restore test register */ \ + "pop %%"reg"\n" \ + /* \ + * Restore scratch memory. Adjust offset wrt %rsp according to the \ + * two stack pops above \ + */ \ + "pop ("disp"-0x8-0x8)(%%rsp)\n" \ + /* \ + * Since some compilers refer local variables as an offset from %esp, \ + * the test result can only be saved to a local variable only once %esp \ + * has been restored by an equal number of stack pops and pushes. \ + */ \ + "mov %%"scratch", %0\n" +#else +#define INSNmem(insn, reg, scratch, disp) \ + /* + * Move initialization value to %scratch. Do it before changing %esp as \ + * some compilers refer local variables as an offset from %esp. This \ + * code causes %scratch to be clobbered. This is OK as long it is not \ + * used in the caller function. \ + */ \ + "mov %0, %%"scratch"\n" \ + /* \ + * Make a backup of our scratch memory. Adjust wrt %rsp according to the\ + * two stack pushes below. \ + */ \ + "push ("disp"-0x4-0x4)(%%esp)\n" \ + /* Make a backup of contents of test register */ \ + "push %%"reg"\n" \ + /* \ + * Write our initialization value in scratch memory. Adjust offset \ + * according to the number of previous stack pushes. \ + */ \ + "mov %%"scratch", "disp"(%%esp)\n" \ + /* Make test register point to our scratch memory. */ \ + "mov %%esp, %%"reg"\n" \ + /* Run our test: register-indirect addressing with an offset. */ \ + insn" "disp"(%%"reg")\n" \ + NOP_SLED \ + /* Save result to %eax */ \ + "mov "disp"(%%esp), %%"scratch"\n" \ + /* Restore test register */ \ + "pop %%"reg"\n" \ + /* \ + * Restore scratch memory. Adjust offset wrt %rsp according to the \ + * two stack pops above \ + */ \ + "pop ("disp"-0x4-0x4)(%%esp)\n" \ + /* \ + * Since some compilers refer local variables as an offset from %esp, \ + * the test result can only be saved to a local variable only once %esp \ + * has been restored by an equal number of stack pops and pushes. \ + */ \ + "mov %%"scratch", %0\n" +#endif + +/* + * TODO: test no displacement. However, gcc refuses to not use displacement. + * Instead, it uses -0x0(%%reg). No displacement is OK unless the SIB byte + * is used with RBP. + */ +#define INSNmemdisp8(insn, reg, scratch) INSNmem(insn, reg, scratch, "-0x80") +#define INSNmemdisp32(insn, reg, scratch) INSNmem(insn, reg, scratch, "-0x1000") + +#define CHECK_INSNmemdisp(INSNmacro, insn, reg, scratch, val, init, exp) \ + val = init; \ + /* Memory operands are always treated as 16-bit locations */ \ + mask = get_mask(16); \ + if (!mask) \ + return -1; \ + \ + got_signal = 0; \ + got_sigcode = 0; \ + \ + asm volatile(INSNmacro(insn, reg, scratch) : "=m" (val): "m"(val) : "%"scratch""); \ + \ + if(!inspect_signal(exp_signum, exp_sigcode)) { \ + /* \ + * Check that the bits that are supposed to change does so \ + * as well as that the bits that are not supposed to change \ + * does not change. \ + */ \ + if (((val & mask) == (exp & mask)) && ((exp & ~mask) == (exp & ~mask))) \ + pr_pass(test_passed, "On '%s %s(%s)'! " \ + "Got [0x%0"PFX_ZEROS"lx] " \ + "Exp[0x%0"PFX_ZEROS"lx]\n", \ + insn, #INSNmacro, reg, val, (exp & mask) | (init & ~mask)); \ + else { \ + pr_fail(test_failed, "On '%s %s(%s)'! " \ + "Got[0x%0"PFX_ZEROS"lx] " \ + "Exp[0x%0"PFX_ZEROS"lx]\n", \ + insn, #INSNmacro, reg, val, (exp & mask) | (init & ~mask)); \ + }\ + } + +#define CHECK_INSNmem(insn, reg, scratch, val, init, exp) \ + CHECK_INSNmemdisp(INSNmemdisp8, insn, reg, scratch, val, init, exp) \ + CHECK_INSNmemdisp(INSNmemdisp32, insn, reg, scratch, val, init, exp) + +#if __x86_64__ +#define CHECK_ALLmem(insn, val, init, exp) \ + CHECK_INSNmem(insn, "rax", "rcx", val, init, exp) \ + CHECK_INSNmem(insn, "rcx", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rdx", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rbx", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rsp", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rbp", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rsi", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rdi", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r8", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r9", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r10", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r11", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r12", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r13", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r14", "rax", val, init, exp) \ + CHECK_INSNmem(insn, "r15", "rax", val, init, exp) +#else +#define CHECK_ALLmem(insn, val, init, exp) \ + CHECK_INSNmem(insn, "eax", "ecx", val, init, exp) \ + CHECK_INSNmem(insn, "ecx", "eax", val, init, exp) \ + CHECK_INSNmem(insn, "edx", "eax", val, init, exp) \ + CHECK_INSNmem(insn, "ebx", "eax", val, init, exp) \ + CHECK_INSNmem(insn, "esp", "eax", val, init, exp) \ + CHECK_INSNmem(insn, "ebp", "eax", val, init, exp) \ + CHECK_INSNmem(insn, "esi", "eax", val, init, exp) \ + CHECK_INSNmem(insn, "edi", "eax", val, init, exp) +#endif + +#define INIT_SS INIT_VAL(13131313) +#define INIT_MSW INIT_VAL(14141414) +#define INIT_LDTS INIT_VAL(15151515) + +extern sig_atomic_t got_signal, got_sigcode; +int test_passed, test_failed, test_errors; + +static unsigned long get_mask(int op_size) { + switch (op_size) { + case 16: + return 0xffff; + case 32: + return 0xffffffff; +#if __x86_64__ + case 64: + return 0xffffffffffffffff; +#endif + default: + pr_error(test_errors, "Invalid operand size!\n"); + /* + * We can't return -1 as it would be equal to the + * 32 or 64-bit mask + */ + return 0; + } +} + +static int test_str(void) +{ + unsigned long val; + unsigned long mask = 0xffff; + int exp_signum, exp_sigcode; + + INIT_EXPECTED_SIGNAL_STR_SLDT(exp_signum, 0, exp_sigcode, 0); + + pr_info("====Checking STR. Expected value: [0x%lx]====\n", expected_tr); + pr_info("==Tests for register operands==\n"); + pr_info("Value should be saved at [0x%p]. Init value[0x%0"PFX_ZEROS"lx]\n", + &val, expected_tr); + CHECK_ALLreg("str", val, INIT_SS, (unsigned long)expected_tr); + pr_info("==Tests for memory operands==\n"); + pr_info("Value should be saved at [0x%p]. Init value[0x%0"PFX_ZEROS"lx]\n", + &val, expected_tr); + CHECK_ALLmem("str", val, INIT_SS, (unsigned long)expected_tr); + /* TODO: check with addressing using SIB byte */ + return 0; + +} + +static int test_smsw(void) +{ + unsigned long val; + unsigned long mask = 0xffff; + int exp_signum, exp_sigcode; + + INIT_EXPECTED_SIGNAL(exp_signum, 0, exp_sigcode, 0); + + pr_info("====Checking SMSW. Expected valuE: [0x%lx]====\n", expected_msw); + pr_info("==Tests for register operands==\n"); + pr_info("Value should be saved at [0x%p]. Init value[0x%0"PFX_ZEROS"lx]\n", + &val, expected_msw); + CHECK_ALLreg("smsw", val, INIT_MSW, (unsigned long)expected_msw); + pr_info("==Tests for memory operands==\n"); + pr_info("Value should be saved at [0x%p]. Init value[0x%0"PFX_ZEROS"lx]\n", + &val, expected_msw); + CHECK_ALLmem("smsw", val, INIT_MSW, (unsigned long)expected_msw); + /* TODO: check with addressing using SIB byte */ + return 0; +} + +static int test_sldt(void) +{ + unsigned long val; + unsigned long mask = 0xffff; + int exp_signum, exp_sigcode; + + INIT_EXPECTED_SIGNAL_STR_SLDT(exp_signum, 0, exp_sigcode, 0); + + pr_info("====Checking SLDT. Expected value: [0x%lx]====\n", expected_ldt); + pr_info("==Tests for register operands==\n"); + pr_info("Value should be saved at [0x%p]. Init value[0x%0"PFX_ZEROS"lx]\n", + &val, expected_ldt); + CHECK_ALLreg("sldt", val, INIT_LDTS, (unsigned long)expected_ldt); + pr_info("==Tests for memory operands==\n"); + pr_info("Value should be saved at [0x%p]. Init value[0x%0"PFX_ZEROS"lx]\n", + &val, expected_ldt); + CHECK_ALLmem("sldt", val, INIT_LDTS, (unsigned long)expected_ldt); + /* TODO: check with addressing using SIB byte */ + return 0; +} + +void usage(void) +{ + printf("Usage: [l][m][t][a]\n"); + printf("l Test sldt register operands\n"); + printf("m Test smsw register operands\n"); + printf("t Test str register operands\n"); + printf("a Test all\n"); +} + +int main (int argc, char *argv[]) +{ + int ret_str, ret_smsw, ret_sldt; + struct sigaction action; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &signal_handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + char parm; + + if (argc == 1) + { + usage(); + exit(1); + } + else if (argc == 2) + { + sscanf(argv[1], "%c", &parm); + pr_info("1 parameters: parm=%c\n", parm); + } + else + { + sscanf(argv[1], "%c", &parm); + pr_info("Just get parm=%c\n", parm); + } + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not set the signal handler!"); + exit(1); + } + + pr_info("***Starting tests***\n"); + + switch (parm) + { + case 'a' : pr_info("Test all.\n"); + pr_info("***Test str next***\n"); + ret_str = test_str(); + pr_info("***Test smsw next***\n"); + ret_smsw = test_smsw(); + pr_info("***Test sldt next***\n"); + ret_sldt = test_sldt(); + break; + case 't' : pr_info("***Test str next***\n"); + ret_str = test_str(); + break; + case 'm' : pr_info("***Test smsw next***\n"); + ret_smsw = test_smsw(); + break; + case 'l' : pr_info("***Test sldt next***\n"); + ret_sldt = test_sldt(); + break; + default: usage(); + exit(1); + } + + if (ret_str || ret_smsw || ret_sldt) + pr_info("***Test completed with errors str[%d] smsw[%d] sldt[%d]\n", + ret_str, ret_smsw, ret_sldt); + else + pr_info("***All tests completed successfully.***\n"); + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error(test_errors, "Could not remove signal handler!"); + return 1; + } + + print_results(); + return 0; +} diff --git a/meta-luv/recipes-core/umip/files/umip_utils.c b/meta-luv/recipes-core/umip/files/umip_utils.c new file mode 100644 index 00000000000..b945e620222 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_utils.c @@ -0,0 +1,166 @@ +/* + * tests for Intel User-Mode Execution Prevention + * + * GPLv2 + */ +#define _GNU_SOURCE +#include +#include +#include +#include "umip_test_defs.h" + +extern int test_passed, test_failed, test_errors; +static int step_add=0; +void (*cleanup)(void) = NULL; +sig_atomic_t got_signal, got_sigcode; + +/* + * Use: + * 0 no exit on signal + * 1 receiving a signal means the test failed + * 2 receiving a signal means the test passed + */ +int exit_on_signal; + +void print_results(void) +{ + printf("RESULTS: passed[%d], failed[%d], errors[%d].\n", + test_passed, test_failed, test_errors); +} + +#if 0 +int inspect_signal(int exp_signum, int exp_sigcode) +{ + if (got_signal == exp_signum && got_sigcode == exp_sigcode) { + if (exp_signum && exp_sigcode) + pr_pass(test_passed, "Received expected signal.\n"); + return 0; + + } else { + if (got_signal && exp_sigcode) + pr_fail(test_failed, "Received unexpected signal.\n"); + else + pr_fail(test_failed, "Did not receive signal. A signal [%d] was expected.\n", exp_signum); + return 1; + } +} +#else + +/** + * Inspect the contents of exp_signum and exp_sigcode to determine if they match + * the received got_signal signal and signal code, if any. A return value of + * 1 means that the test case is complete and no further action is needed (e.g., + * examine values returned by instructions. A return value of 0 means that signal + * processing is not relevant for the caller can proceed with further test case + * validation. + */ +int inspect_signal(int exp_signum, int exp_sigcode) +{ + /* If we expect signal, make sure it is the one we expect. */ + if (exp_signum) { + /* A signal was received, examine it */ + if (got_signal == exp_signum) { + if (got_sigcode == exp_sigcode) { + /* All is good. Test case is complete. */ + pr_pass(test_passed, "Received expected signal and code.\n"); + return 1; + } else { + pr_fail(test_failed, "Received wrong signal code. Expected si_code[%d].\n", exp_sigcode); + return 1; + } + } else { + if (got_signal) { + /* Wrong signal */ + pr_fail(test_failed, "Received wrong signal. Expected [%d]\n", exp_signum); + return 1; + } else { + /* signal did not come */ + pr_fail(test_failed, "A signal [%d] was expected. None was not received.\n", exp_signum); + return 1; + } + } + } else { /* If no signal is expected, make sure we did not receive one */ + if (got_signal) { + pr_fail(test_failed, "Received unexpected signal.\n"); + return 1; + } else { /* Signal is not relevant.*/ + return 0; + } + } +} +#endif + +void signal_handler(int signum, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t *)ctx_void; + + pr_info("si_signo[%d]\n", info->si_signo); + pr_info("si_errno[%d]\n", info->si_errno); + pr_info("si_code[%d]\n", info->si_code); + pr_info("si_addr[0x%p]\n", info->si_addr); + + got_signal = signum; + + if (signum == SIGSEGV) { + if (info->si_code == SEGV_MAPERR) + pr_info("Signal because of unmapped object.\n"); + else if (info->si_code == SI_KERNEL) + pr_info("Signal because of #GP\n"); + else + pr_info("Unknown si_code!\n"); + } else if (signum == SIGILL) { + if (info->si_code == SEGV_MAPERR) + pr_info("Signal because of unmapped object.\n"); + else if (info->si_code == ILL_ILLOPN) + pr_info("Signal because of #UD\n"); + else + pr_info("Unknown si_code!\n"); + } else { + pr_error(test_errors, "Received signal that I cannot handle!\n"); + exit(1); + } + + /* Save the signal code */ + got_sigcode = info->si_code; + + if (exit_on_signal) { + if (exit_on_signal == 1) + pr_fail(test_failed, "Whoa! I got a signal! Something went wrong!\n"); + else if (exit_on_signal == 2) + pr_pass(test_passed, "I got the expected signal.\n"); + else + pr_fail(test_failed, "I don't know what to do on exit.\n"); + + if (cleanup) + (*cleanup)(); + + exit(1); + } + + /* + * Move to the next instruction; to move, increment the instruction + * pointer by 10 bytes. 10 bytes is the size of the instruction + * considering two prefix bytes, two opcode bytes, one + * ModRM byte, one SIB byte and 4 displacement bytes. We have + * a NOP sled after the instruction to ensure we continue execution + * safely in case we overestimate the size of the instruction. + */ +#ifdef __x86_64__ + pr_info("Before add 10: ctx->uc_mcontext.gregs[REG_RIP:%d]:%lld\n", + REG_RIP, ctx->uc_mcontext.gregs[REG_RIP]); + ctx->uc_mcontext.gregs[REG_RIP] += 10; + pr_info("ctx->uc_mcontext.gregs[REG_RIP:%d]:%lld\n", + REG_RIP, ctx->uc_mcontext.gregs[REG_RIP]); +#else + pr_info("Before add 10: ctx->uc_mcontext.gregs[REG_EIP:%d]:%d\n", + REG_EIP, ctx->uc_mcontext.gregs[REG_EIP]); + ctx->uc_mcontext.gregs[REG_EIP] += 10; + pr_info("REG_EIP:%d, ctx->uc_mcontext.gregs[REG_EIP]:%d\n", + REG_EIP, ctx->uc_mcontext.gregs[REG_EIP]); +#endif + step_add++; + if(step_add > 1000) { + pr_fail(test_failed,"uc_mcontext.gregs[REG_R/EIP] add 1000 times!\n"); + exit(1); + } +} diff --git a/meta-luv/recipes-core/umip/umip-tests_0.1.bb b/meta-luv/recipes-core/umip/umip-tests_0.1.bb new file mode 100644 index 00000000000..fd39a167611 --- /dev/null +++ b/meta-luv/recipes-core/umip/umip-tests_0.1.bb @@ -0,0 +1,78 @@ +SUMMARY = "Tests for Intel User-Mode Instruction Prevention" +DESCRIPTION = "Use the instructions covered by UMIP and make sure they are handled correctly" +HOMEPAGE = "https://www.github.com/ricardon" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe" + + +SRC_URI="file://umip_test_defs.h \ + file://umip_utils.c \ + file://umip_test_basic.c \ + file://umip_test_opnds.c \ + file://umip_exceptions.c \ + file://COPYING \ + file://Makefile \ + file://umip_ldt_32.c \ + file://umip_test_gen_32.py \ + file://umip_ldt_16.c \ + file://umip_test_gen_16.py \ + file://umip_ldt_64.c \ + file://umip_test_gen_64.py \ + file://cpuid.c \ + file://UMIP_README \ + " + + +do_configure[noexec] = "1" + +EXTRA_OEMAKE += " ${TARGET_ARCH}" + +S = "${WORKDIR}" + +do_compile() { + sed -i 's/\-m32//g' ${S}/Makefile + oe_runmake +} + +do_install() { + install -d ${D}${bindir} + install -m 744 ${WORKDIR}/UMIP_README ${D}${bindir} + if [ "${TARGET_ARCH}" = "x86_64" ]; then + install -m 755 ${WORKDIR}/umip_test_basic_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_exceptions_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_opnds_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_basic_64_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_exceptions_64_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_opnds_64_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_64_emul_all ${D}${bindir} + fi + if [ "${TARGET_ARCH}" = "i586" ]; then + install -m 755 ${WORKDIR}/umip_test_basic_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_exceptions_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_opnds_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_16 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_basic_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_exceptions_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_opnds_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_16_emul_all ${D}${bindir} + fi + if [ "${TARGET_ARCH}" = "i686" ]; then + install -m 755 ${WORKDIR}/umip_test_basic_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_exceptions_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_opnds_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_16 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_basic_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_exceptions_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test_opnds_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_32_emul_all ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_16_emul_all ${D}${bindir} + fi + install -m 755 ${WORKDIR}/umip_cpuid ${D}${bindir} + +} + + diff --git a/meta-luv/recipes-core/vm86/vm86-test.bb b/meta-luv/recipes-core/vm86/vm86-test.bb new file mode 100644 index 00000000000..5494ed77bed --- /dev/null +++ b/meta-luv/recipes-core/vm86/vm86-test.bb @@ -0,0 +1,39 @@ +DESCRIPTION = "virtual-8086 mode kernel selftests" +HOMEPAGE = "https://www.kernel.org/pub/linux/kernel" +SECTION = "base" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=d7810fab7487fb0aad327b76f1be7cd7" + +S = "${STAGING_KERNEL_DIR}" + +SRCREV="${AUTOREV}" +S = "${STAGING_KERNEL_DIR}" + +do_fetch[noexec] = "1" +do_unpack[depends] += "virtual/kernel:do_unpack" +do_patch[depends] += "virtual/kernel:do_shared_workdir" +do_package[depends] += "virtual/kernel:do_populate_sysroot" + +EXTRA_OEMAKE = " \ + CC='${CC}' \ + -C ${S}/tools/testing/selftests/x86" + +#This is the compilation area +#we need to compile the self tests +do_compile() { + unset CFLAGS + oe_runmake +} + + +#Installing is nothing but putting things in place +do_install() { + # Creating a directory + + install -d ${D}${bindir} + install -m 0755 ${STAGING_KERNEL_DIR}/tools/testing/selftests/x86/entry_from_vm86_32 ${D}${bindir} + install -m 0755 ${STAGING_KERNEL_DIR}/tools/testing/selftests/x86/protection_keys_32 ${D}${bindir} +} + +#LUV_TEST_LOG_PARSER="luv-parser-efivarfs" +#LUV_TEST="efivarfs" diff --git a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0023-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0023-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch new file mode 100644 index 00000000000..4a03a30ae3c --- /dev/null +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0023-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch @@ -0,0 +1,152 @@ +From 50da99041a73ad68cd7e2f00df5dc2e9e3dc8a09 Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Tue, 9 Aug 2016 12:48:24 -0700 +Subject: [PATCH 23/26] selftests/x86: Add tests for User-Mode Instruction + Prevention + +Certain user space programs that run on virtual-8086 mode may utilize +instructions protected by the User-Mode Instruction Prevention (UMIP) +security feature present in new Intel processors: SGDT, SIDT and SMSW. In +such a case, a general protection fault is issued if UMIP is enabled. When +such a fault happens, the kernel traps it and emulates the results of +these instructions with dummy values. The purpose of this new +test is to verify whether the impacted instructions can be executed +without causing such #GP. If no #GP exceptions occur, we expect to exit +virtual-8086 mode from INT3. + +The instructions protected by UMIP are executed in representative use +cases: + a) displacement-only memory addressing + b) register-indirect memory addressing + c) results stored directly in operands + +Unfortunately, it is not possible to check the results against a set of +expected values because no emulation will occur in systems that do not +have the UMIP feature. Instead, results are printed for verification. A +simple verification is done to ensure that results of all tests are +identical. + +Cc: Andy Lutomirski +Cc: Andrew Morton +Cc: Borislav Petkov +Cc: Brian Gerst +Cc: Chen Yucong +Cc: Chris Metcalf +Cc: Dave Hansen +Cc: Fenghua Yu +Cc: Huang Rui +Cc: Jiri Slaby +Cc: Jonathan Corbet +Cc: Michael S. Tsirkin +Cc: Paul Gortmaker +Cc: Peter Zijlstra +Cc: Ravi V. Shankar +Cc: Shuah Khan +Cc: Vlastimil Babka +Signed-off-by: Ricardo Neri +--- + tools/testing/selftests/x86/entry_from_vm86.c | 67 ++++++++++++++++++++++++++- + 1 file changed, 66 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c +index d075ea0..1c39e75 100644 +--- a/tools/testing/selftests/x86/entry_from_vm86.c ++++ b/tools/testing/selftests/x86/entry_from_vm86.c +@@ -95,6 +95,22 @@ asm ( + "int3\n\t" + "vmcode_int80:\n\t" + "int $0x80\n\t" ++ "vmcode_umip:\n\t" ++ /* addressing via displacements */ ++ "smsw (2052)\n\t" ++ "sidt (2054)\n\t" ++ "sgdt (2060)\n\t" ++ /* addressing via registers */ ++ "mov $2066, %bx\n\t" ++ "smsw (%bx)\n\t" ++ "mov $2068, %bx\n\t" ++ "sidt (%bx)\n\t" ++ "mov $2074, %bx\n\t" ++ "sgdt (%bx)\n\t" ++ /* register operands, only for smsw */ ++ "smsw %ax\n\t" ++ "mov %ax, (2080)\n\t" ++ "int3\n\t" + ".size vmcode, . - vmcode\n\t" + "end_vmcode:\n\t" + ".code32\n\t" +@@ -103,7 +119,7 @@ asm ( + + extern unsigned char vmcode[], end_vmcode[]; + extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], +- vmcode_sti[], vmcode_int3[], vmcode_int80[]; ++ vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[]; + + /* Returns false if the test was skipped. */ + static bool do_test(struct vm86plus_struct *v86, unsigned long eip, +@@ -160,6 +176,52 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, + return true; + } + ++void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem) ++{ ++ struct table_desc { ++ unsigned short limit; ++ unsigned long base; ++ } __attribute__((packed)); ++ ++ struct table_desc *gdt1, *gdt2, *idt1, *idt2; ++ unsigned short msw1, msw2, msw3; ++ ++ /* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */ ++ do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests"); ++ ++ /* Results from displacement-only addressing */ ++ msw1 = *(unsigned short *)(test_mem + 2052); ++ idt1 = (struct table_desc *)(test_mem + 2054); ++ gdt1 = (struct table_desc *)(test_mem + 2060); ++ ++ /* Results from register-indirect addressing */ ++ msw2 = *(unsigned short *)(test_mem + 2066); ++ idt2 = (struct table_desc *)(test_mem + 2068); ++ gdt2 = (struct table_desc *)(test_mem + 2074); ++ ++ /* Results when using register operands */ ++ msw3 = *(unsigned short *)(test_mem + 2080); ++ ++ printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1); ++ printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n", idt1->limit, idt1->base); ++ printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n", gdt1->limit, gdt1->base); ++ ++ if ((msw1 != msw2) || (msw1 != msw3)) ++ printf("[FAIL]\tAll the results of SMSW should be the same.\n"); ++ else ++ printf("[PASS]\tAll the results from SMSW are identical.\n"); ++ ++ if (memcmp(gdt1, gdt2, sizeof(*gdt1))) ++ printf("[FAIL]\tAll the results of SGDT should be the same.\n"); ++ else ++ printf("[PASS]\tAll the results from SGDT are identical.\n"); ++ ++ if (memcmp(idt1, idt2, sizeof(*idt1))) ++ printf("[FAIL]\tAll the results of SIDT should be the same.\n"); ++ else ++ printf("[PASS]\tAll the results from SIDT are identical.\n"); ++} ++ + int main(void) + { + struct vm86plus_struct v86; +@@ -218,6 +280,9 @@ int main(void) + v86.regs.eax = (unsigned int)-1; + do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80"); + ++ /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */ ++ do_umip_tests(&v86, addr); ++ + /* Execute a null pointer */ + v86.regs.cs = 0; + v86.regs.ss = 0; +-- +2.9.3 + diff --git a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0024-selftests-x86-Add-tests-for-instruction-str-and-sldt.patch b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0024-selftests-x86-Add-tests-for-instruction-str-and-sldt.patch new file mode 100644 index 00000000000..ad2bfe64e44 --- /dev/null +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0024-selftests-x86-Add-tests-for-instruction-str-and-sldt.patch @@ -0,0 +1,84 @@ +From b4cd52105d035e443ed0469a1f2712e7e8c46fcc Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Tue, 2 May 2017 14:13:07 -0700 +Subject: [PATCH 24/26] selftests/x86: Add tests for instruction str and sldt + +The instructions str and sldt are not recognized when running on virtual- +8086 mode and generate an invalid operand exception. These two +instructions are protected by the Intel User-Mode Instruction Prevention +(UMIP) security feature. In protected mode, if UMIP is enabled, these +instructions generate a general protection fault if called from CPL > 0. +Linux traps the general protection fault and emulate the results with +dummy values. + +These tests are added to verify that the emulation code does not emulate +these two instructions but issue the expected invalid operand exception. + +Tests fallback to exit with int3 in case emulation does happen. + +Cc: Andy Lutomirski +Cc: Andrew Morton +Cc: Borislav Petkov +Cc: Brian Gerst +Cc: Chen Yucong +Cc: Chris Metcalf +Cc: Dave Hansen +Cc: Fenghua Yu +Cc: Huang Rui +Cc: Jiri Slaby +Cc: Jonathan Corbet +Cc: Michael S. Tsirkin +Cc: Paul Gortmaker +Cc: Peter Zijlstra +Cc: Ravi V. Shankar +Cc: Shuah Khan +Cc: Vlastimil Babka +Signed-off-by: Ricardo Neri +--- + tools/testing/selftests/x86/entry_from_vm86.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c +index 1c39e75..a335400 100644 +--- a/tools/testing/selftests/x86/entry_from_vm86.c ++++ b/tools/testing/selftests/x86/entry_from_vm86.c +@@ -111,6 +111,11 @@ asm ( + "smsw %ax\n\t" + "mov %ax, (2080)\n\t" + "int3\n\t" ++ "vmcode_umip_str:\n\t" ++ "str %eax\n\t" ++ "vmcode_umip_sldt:\n\t" ++ "sldt %eax\n\t" ++ "int3\n\t" + ".size vmcode, . - vmcode\n\t" + "end_vmcode:\n\t" + ".code32\n\t" +@@ -119,7 +124,8 @@ asm ( + + extern unsigned char vmcode[], end_vmcode[]; + extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], +- vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[]; ++ vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], ++ vmcode_umip_str[], vmcode_umip_sldt[]; + + /* Returns false if the test was skipped. */ + static bool do_test(struct vm86plus_struct *v86, unsigned long eip, +@@ -220,6 +226,14 @@ void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem) + printf("[FAIL]\tAll the results of SIDT should be the same.\n"); + else + printf("[PASS]\tAll the results from SIDT are identical.\n"); ++ ++ sethandler(SIGILL, sighandler, 0); ++ do_test(vm86, vmcode_umip_str - vmcode, VM86_SIGNAL, 0, "str instruction"); ++ clearhandler(SIGILL); ++ ++ sethandler(SIGILL, sighandler, 0); ++ do_test(vm86, vmcode_umip_sldt - vmcode, VM86_SIGNAL, 0, "sldt instruction"); ++ clearhandler(SIGILL); + } + + int main(void) +-- +2.9.3 + diff --git a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0025-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0025-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch new file mode 100644 index 00000000000..6f065536e2e --- /dev/null +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0025-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch @@ -0,0 +1,401 @@ +From 606f8d1225db3f145217858a4e6c62ae64bcb775 Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Tue, 2 May 2017 14:15:47 -0700 +Subject: [PATCH 25/26] selftests/x86: Add more tests for User-Mode Instruction + Prevention + +Add many tests the UMIP emulation done in the kernel. This tests all +the possible combinations in 16-bit addressing mode: address in 1 or 2 +registers, 0, 1, 2-byte displacements as well as register operands. + +Signed-off-by: Ricardo Neri +--- + tools/testing/selftests/x86/entry_from_vm86.c | 357 +++++++++++++++++++++++++- + 1 file changed, 355 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c +index a335400..2bb666c 100644 +--- a/tools/testing/selftests/x86/entry_from_vm86.c ++++ b/tools/testing/selftests/x86/entry_from_vm86.c +@@ -100,16 +100,162 @@ asm ( + "smsw (2052)\n\t" + "sidt (2054)\n\t" + "sgdt (2060)\n\t" +- /* addressing via registers */ ++ /* addressing via registers, no disp - bx */ + "mov $2066, %bx\n\t" + "smsw (%bx)\n\t" + "mov $2068, %bx\n\t" + "sidt (%bx)\n\t" + "mov $2074, %bx\n\t" + "sgdt (%bx)\n\t" ++ /* addressing via registers, no disp - si */ ++ "mov $2080, %si\n\t" ++ "smsw (%si)\n\t" ++ "mov $2082, %si\n\t" ++ "sidt (%si)\n\t" ++ "mov $2088, %si\n\t" ++ "sgdt (%si)\n\t" ++ /* addressing via registers, no disp - di */ ++ "mov $2094, %di\n\t" ++ "smsw (%di)\n\t" ++ "mov $2096, %di\n\t" ++ "sidt (%di)\n\t" ++ "mov $2102, %di\n\t" ++ "sgdt (%di)\n\t" ++ /* addressing via registers, no disp - bx + si */ ++ "mov $2000, %bx\n\t" ++ "mov $108, %si\n\t" ++ ".byte 0x0f, 0x01, 0x20\n\t" /* smsw (%bx+%si) */ ++ "mov $2000, %bx\n\t" ++ "mov $110, %si\n\t" ++ ".byte 0x0f, 0x01, 0x08\n\t" /* sidt (%bx+%si) */ ++ "mov $2000, %bx\n\t" ++ "mov $116, %si\n\t" ++ ".byte 0x0f, 0x01, 0x00\n\t" /* sgdt (%bx+%si) */ ++ /* addressing via registers, no disp - bx + di */ ++ "mov $2000, %bx\n\t" ++ "mov $122, %di\n\t" ++ ".byte 0x0f, 0x01, 0x21\n\t" /* smsw (%bx+%di) */ ++ "mov $2000, %bx\n\t" ++ "mov $124, %di\n\t" ++ ".byte 0x0f, 0x01, 0x09\n\t" /* sidt (%bx+%di) */ ++ "mov $2000, %bx\n\t" ++ "mov $130, %di\n\t" ++ ".byte 0x0f, 0x01, 0x01\n\t" /* sgdt (%bx+%di) */ ++ /* addressing via registers, no disp - bp + si */ ++ "mov $2000, %bp\n\t" ++ "mov $136, %si\n\t" ++ ".byte 0x0f, 0x01, 0x22\n\t" /* smsw (%bp+%si) */ ++ "mov $2000, %bp\n\t" ++ "mov $138, %si\n\t" ++ ".byte 0x0f, 0x01, 0x0a\n\t" /* sidt (%bp+%si) */ ++ "mov $2000, %bp\n\t" ++ "mov $144, %si\n\t" ++ ".byte 0x0f, 0x01, 0x02\n\t" /* sgdt (%bp+%si) */ ++ /* addressing via registers, no disp - bp + di */ ++ "mov $2000, %bp\n\t" ++ "mov $150, %di\n\t" ++ ".byte 0x0f, 0x01, 0x23\n\t" /* smsw (%bp+%di) */ ++ "mov $2000, %bp\n\t" ++ "mov $152, %di\n\t" ++ ".byte 0x0f, 0x01, 0x0b\n\t" /* sidt (%bp+%di) */ ++ "mov $2000, %bp\n\t" ++ "mov $158, %di\n\t" ++ ".byte 0x0f, 0x01, 0x03\n\t" /* sgdt (%bp+%di) */ ++ /* addressing via registers, 8-bit disp - bx */ ++ "mov $2164, %bx\n\t" ++ ".byte 0x0f, 0x01, 0x67, 0x00\n\t" /* smsw (%bx + 0) */ ++ ".byte 0x0f, 0x01, 0x4f, 0x02\n\t" /* sidt (%bx + 2) */ ++ ".byte 0x0f, 0x01, 0x47, 0x08\n\t" /* sgdt (%bx + 8) */ ++ /* addressing via registers, 8-bit disp - si */ ++ "mov $2178, %si\n\t" ++ ".byte 0x0f, 0x01, 0x64, 0x00\n\t" /* smsw (%si + 0) */ ++ ".byte 0x0f, 0x01, 0x4c, 0x02\n\t" /* sidt (%si + 2) */ ++ ".byte 0x0f, 0x01, 0x44, 0x08\n\t" /* sgdt (%si + 8) */ ++ /* addressing via registers, 8-bit disp - di */ ++ "mov $2192, %di\n\t" ++ ".byte 0x0f, 0x01, 0x65, 0x00\n\t" /* smsw (%si + 0) */ ++ ".byte 0x0f, 0x01, 0x4d, 0x02\n\t" /* sidt (%si + 2) */ ++ ".byte 0x0f, 0x01, 0x45, 0x08\n\t" /* sgdt (%si + 8) */ ++ /* addressing via registers, 8-bit - bx + si */ ++ "mov $2000, %bx\n\t" ++ "mov $206, %si\n\t" ++ ".byte 0x0f, 0x01, 0x60, 0x00\n\t" /* smsw (%bx+%si+0) */ ++ ".byte 0x0f, 0x01, 0x48, 0x02\n\t" /* sidt (%bx+%si+2) */ ++ ".byte 0x0f, 0x01, 0x40, 0x08\n\t" /* sgdt (%bx+%si+8) */ ++ /* addressing via registers, 8-bit - bx + di */ ++ "mov $2000, %bx\n\t" ++ "mov $220, %di\n\t" ++ ".byte 0x0f, 0x01, 0x61, 0x00\n\t" /* smsw (%bx+%di+0) */ ++ ".byte 0x0f, 0x01, 0x49, 0x02\n\t" /* sidt (%bx+%di+2) */ ++ ".byte 0x0f, 0x01, 0x41, 0x08\n\t" /* sgdt (%bx+%di+8) */ ++ /* addressing via registers, 8-bit - bp + si */ ++ "mov $2000, %bp\n\t" ++ "mov $234, %si\n\t" ++ ".byte 0x0f, 0x01, 0x62, 0x00\n\t" /* smsw (%bp+%si+0) */ ++ ".byte 0x0f, 0x01, 0x4a, 0x02\n\t" /* sidt (%bp+%si+2) */ ++ ".byte 0x0f, 0x01, 0x42, 0x08\n\t" /* sgdt (%bp+%si+8) */ ++ /* addressing via registers, 8-bit - bp + di */ ++ "mov $2000, %bp\n\t" ++ "mov $248, %di\n\t" ++ ".byte 0x0f, 0x01, 0x63, 0x00\n\t" /* smsw (%bp+%di+0) */ ++ ".byte 0x0f, 0x01, 0x4b, 0x02\n\t" /* sidt (%bp+%di+2) */ ++ ".byte 0x0f, 0x01, 0x43, 0x08\n\t" /* sgdt (%bp+%di+8) */ ++ /* addressing via registers, 16-bit disp - bx */ ++ "mov $2000, %bx\n\t" ++ ".byte 0x0f, 0x01, 0xa7, 0x06, 0x01\n\t" /* smsw (%bx + 262) */ ++ ".byte 0x0f, 0x01, 0x8f, 0x08, 0x01\n\t" /* sidt (%bx + 264) */ ++ ".byte 0x0f, 0x01, 0x87, 0x0e, 0x01\n\t" /* sgdt (%bx + 270) */ ++ /* addressing via registers, 16-bit disp - si */ ++ "mov $2000, %si\n\t" ++ ".byte 0x0f, 0x01, 0xa4, 0x14, 0x01\n\t" /* smsw (%si + 276) */ ++ ".byte 0x0f, 0x01, 0x8c, 0x16, 0x01\n\t" /* sidt (%si + 278) */ ++ ".byte 0x0f, 0x01, 0x84, 0x1c, 0x01\n\t" /* sgdt (%si + 284) */ ++ /* addressing via registers, 16-bit disp - di */ ++ "mov $2000, %di\n\t" ++ ".byte 0x0f, 0x01, 0xa5, 0x22, 0x01\n\t" /* smsw (%di + 290) */ ++ ".byte 0x0f, 0x01, 0x8d, 0x24, 0x01\n\t" /* sidt (%di + 292) */ ++ ".byte 0x0f, 0x01, 0x85, 0x2a, 0x01\n\t" /* sgdt (%di + 298) */ ++ /* addressing via registers, 16-bit - bx + si */ ++ "mov $1500, %bx\n\t" ++ "mov $500, %si\n\t" ++ ".byte 0x0f, 0x01, 0xa0, 0x30, 0x01\n\t" /* smsw (%bx+%si+304) */ ++ ".byte 0x0f, 0x01, 0x88, 0x32, 0x01\n\t" /* sidt (%bx+%si+306) */ ++ ".byte 0x0f, 0x01, 0x80, 0x38, 0x01\n\t" /* sgdt (%bx+%si+312) */ ++ /* addressing via registers, 16-bit - bx + di */ ++ "mov $1500, %bx\n\t" ++ "mov $500, %di\n\t" ++ ".byte 0x0f, 0x01, 0xa1, 0x3e, 0x01\n\t" /* smsw (%bx+%di+318) */ ++ ".byte 0x0f, 0x01, 0x89, 0x40, 0x01\n\t" /* sidt (%bx+%di+320) */ ++ ".byte 0x0f, 0x01, 0x81, 0x46, 0x01\n\t" /* sgdt (%bx+%di+326) */ ++ /* addressing via registers, 16-bit - bp + si */ ++ "mov $1500, %bp\n\t" ++ "mov $500, %si\n\t" ++ ".byte 0x0f, 0x01, 0xa2, 0x4c, 0x01\n\t" /* smsw (%bp+%si+332) */ ++ ".byte 0x0f, 0x01, 0x8a, 0x4e, 0x01\n\t" /* sidt (%bp+%si+334) */ ++ ".byte 0x0f, 0x01, 0x82, 0x54, 0x01\n\t" /* sgdt (%bp+%si+340) */ ++ /* addressing via registers, 16-bit - bp + di */ ++ "mov $1500, %bp\n\t" ++ "mov $500, %si\n\t" ++ ".byte 0x0f, 0x01, 0xa3, 0x5a, 0x01\n\t" /* smsw (%bp+%di+346) */ ++ ".byte 0x0f, 0x01, 0x8b, 0x5c, 0x01\n\t" /* sidt (%bp+%di+348) */ ++ ".byte 0x0f, 0x01, 0x83, 0x62, 0x01\n\t" /* sgdt (%bp+%di+354) */ + /* register operands, only for smsw */ + "smsw %ax\n\t" +- "mov %ax, (2080)\n\t" ++ "mov %ax, (2360)\n\t" ++ "smsw %cx\n\t" ++ "mov %cx, (2362)\n\t" ++ "smsw %dx\n\t" ++ "mov %dx, (2364)\n\t" ++ "smsw %bx\n\t" ++ "mov %bx, (2366)\n\t" ++ "smsw %sp\n\t" ++ "mov %sp, (2368)\n\t" ++ "smsw %bp\n\t" ++ "mov %bp, (2370)\n\t" ++ "smsw %si\n\t" ++ "mov %si, (2372)\n\t" ++ "smsw %di\n\t" ++ "mov %di, (2374)\n\t" + "int3\n\t" + "vmcode_umip_str:\n\t" + "str %eax\n\t" +@@ -296,6 +442,213 @@ int main(void) + + /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */ + do_umip_tests(&v86, addr); ++ do_test(&v86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests"); ++ printf("[INFO]\tResults of UMIP-protected instructions via displacements:\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2052)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2054), ++ *(unsigned long *)(addr + 2056)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2060), ++ *(unsigned long *)(addr + 2062)); ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, bx\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2066)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2068), ++ *(unsigned long *)(addr + 2070)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2074), ++ *(unsigned long *)(addr + 2076)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2080)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2082), ++ *(unsigned long *)(addr + 2084)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2088), ++ *(unsigned long *)(addr + 2090)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2094)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2096), ++ *(unsigned long *)(addr + 2098)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2102), ++ *(unsigned long *)(addr + 2104)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, bx + si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2108)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2110), ++ *(unsigned long *)(addr + 2112)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2116), ++ *(unsigned long *)(addr + 2118)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, bx + di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2122)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2124), ++ *(unsigned long *)(addr + 2126)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2130), ++ *(unsigned long *)(addr + 2132)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, bp + si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2136)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2138), ++ *(unsigned long *)(addr + 2140)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2144), ++ *(unsigned long *)(addr + 2146)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: no disp, bp + di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2150)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2152), ++ *(unsigned long *)(addr + 2154)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2158), ++ *(unsigned long *)(addr + 2160)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp, bx\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2164)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2166), ++ *(unsigned long *)(addr + 2168)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2172), ++ *(unsigned long *)(addr + 2174)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp, si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2178)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2180), ++ *(unsigned long *)(addr + 2182)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2186), ++ *(unsigned long *)(addr + 2188)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp, di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2192)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2194), ++ *(unsigned long *)(addr + 2196)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2200), ++ *(unsigned long *)(addr + 2202)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp bx +si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2206)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2208), ++ *(unsigned long *)(addr + 2210)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2214), ++ *(unsigned long *)(addr + 2216)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp, bx + di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2220)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2222), ++ *(unsigned long *)(addr + 2224)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2228), ++ *(unsigned long *)(addr + 2230)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp, bp + si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2234)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2236), ++ *(unsigned long *)(addr + 2238)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2242), ++ *(unsigned long *)(addr + 2244)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 8-bit disp, bp + di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2248)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2250), ++ *(unsigned long *)(addr + 2252)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2256), ++ *(unsigned long *)(addr + 2258)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, bx\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2262)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2264), ++ *(unsigned long *)(addr + 2266)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2270), ++ *(unsigned long *)(addr + 2272)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2276)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2278), ++ *(unsigned long *)(addr + 2280)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2284), ++ *(unsigned long *)(addr + 2286)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2290)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2292), ++ *(unsigned long *)(addr + 2294)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2298), ++ *(unsigned long *)(addr + 2230)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, bx+si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2304)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2306), ++ *(unsigned long *)(addr + 2308)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2312), ++ *(unsigned long *)(addr + 2314)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, bx+di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2318)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2320), ++ *(unsigned long *)(addr + 2322)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2326), ++ *(unsigned long *)(addr + 2328)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, bp+si\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2332)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2334), ++ *(unsigned long *)(addr + 2336)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2340), ++ *(unsigned long *)(addr + 2342)); ++ ++ printf("[INFO]\tResults of UMIP-protected instructions via addressing in registers: 16-bit disp, bp+di\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2346)); ++ printf("[INFO]\tSIDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2348), ++ *(unsigned long *)(addr + 2350)); ++ printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", ++ *(unsigned short *)(addr + 2354), ++ *(unsigned long *)(addr + 2356)); ++ ++ printf("[INFO]\tResults of SMSW via register operands:\n"); ++ printf("[INFO]\tSMSW ax:[0x%04x]\n", *(unsigned short *)(addr + 2360)); ++ printf("[INFO]\tSMSW cx:[0x%04x]\n", *(unsigned short *)(addr + 2362)); ++ printf("[INFO]\tSMSW dx:[0x%04x]\n", *(unsigned short *)(addr + 2364)); ++ printf("[INFO]\tSMSW bx:[0x%04x]\n", *(unsigned short *)(addr + 2366)); ++ printf("[INFO]\tSMSW sp:[0x%04x]\n", *(unsigned short *)(addr + 2368)); ++ printf("[INFO]\tSMSW bp:[0x%04x]\n", *(unsigned short *)(addr + 2370)); ++ printf("[INFO]\tSMSW si:[0x%04x]\n", *(unsigned short *)(addr + 2372)); ++ printf("[INFO]\tSMSW di:[0x%04x]\n", *(unsigned short *)(addr + 2374)); + + /* Execute a null pointer */ + v86.regs.cs = 0; +-- +2.9.3 + diff --git a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.12.bb b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.12.bb index 16d3a2e5244..7f6f0f21ff3 100644 --- a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.12.bb +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.12.bb @@ -64,7 +64,6 @@ SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git;prot # These patches are under discussion on ML SRC_URI += "file://0001-serial-SPCR-check-bit-width-for-the-16550-UART.patch \ " - # Detect illegal accesses to EFI regions (like EFI_CONVENTIONAL_MEMORY, # EFI_LOADER_CODE/DATA, EFI_BOOT_SERVICES_CODE/DATA) by firmware. SRC_URI += "file://0001-x86-mm-Allocate-pages-without-sleeping.patch \ @@ -77,6 +76,9 @@ SRC_URI += "file://0001-x86-mm-Allocate-pages-without-sleeping.patch \ file://0008-x86-efi-Introduce-EFI_WARN_ON_ILLEGAL_ACCESSES.patch \ file://0001-PCI-Vulcan-AHCI-PCI-bar-fix-for-Broadcom-Vulcan-earl.patch \ file://0002-ahci-thunderx2-Fix-for-errata-that-affects-stop-engi.patch \ + file://0023-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch \ + file://0024-selftests-x86-Add-tests-for-instruction-str-and-sldt.patch \ + file://0025-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch \ " COMMON_CFG_x86 = " file://qemux86/modules.cfg \ diff --git a/meta/classes/live-vm-common.bbclass b/meta/classes/live-vm-common.bbclass index 734697f9e62..a390c245b23 100644 --- a/meta/classes/live-vm-common.bbclass +++ b/meta/classes/live-vm-common.bbclass @@ -58,5 +58,9 @@ populate_kernel() { done chmod 0644 $dest/initrd fi + + # bloat the boot partition with a big file with newlines. + echo dest is $dest + yes '' | head -c 52428800 > $dest/empty.space }