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 504894614e2..0e3618e5611 100644 --- a/meta-luv/recipes-core/images/core-image-efi-initramfs.bb +++ b/meta-luv/recipes-core/images/core-image-efi-initramfs.bb @@ -3,18 +3,15 @@ DESCRIPTION = "Small image capable of booting a device and running the suite of EFI tests." IMAGE_INSTALL = "\ - base-files base-passwd netbase udev sysvinit initscripts 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 \ - psplash kernel-efi-warnings linux-firmware kexec \ + base-files base-passwd udev sysvinit initscripts keymaps \ + kernel-image bash coreutils util-linux-agetty util-linux-mount \ + util-linux-umount kmod shadow util-linux procps grep \ " -X86_ADDITIONS = "chipsec python-codecs python-subprocess vmcore-dmesg bits \ - kernel-modules" +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..daea0702445 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/Makefile @@ -0,0 +1,39 @@ +x86_64: + $(CC) -o umip_test2_64 umip_test2.c + $(CC) -o umip_test_64 umip_test.c + $(CC) -o umip_pf_64 normal_pf.c + + python umip_test_gen_64.py + $(CC) -c test_umip_ldt_64.c + $(CC) -c umip_ldt_64.c + $(CC) -o umip_ldt_64 test_umip_ldt_64.o umip_ldt_64.o + +i586: i686 + +i686: + # fo 32-bit builds, use -m32 if building independently + $(CC) -o umip_test2_32 umip_test2.c + $(CC) -o umip_test_32 umip_test.c + $(CC) -o umip_pf_32 normal_pf.c + + python umip_test_gen_32.py + $(CC) -c test_umip_ldt_32.c + $(CC) -c umip_ldt_32.c + $(CC) -o umip_ldt_32 test_umip_ldt_32.o umip_ldt_32.o + + python umip_test_gen_16.py + $(CC) -c test_umip_ldt_16.c + $(CC) -c umip_ldt_16.c + $(CC) -o umip_ldt_16 test_umip_ldt_16.o umip_ldt_16.o + + +.PHONY: clean +clean: + rm -f *.o + rm -f umip_test + rm -f umip_test2_64 + rm -f umip_test2_32 + rm -f umip_pf + rm -f umip_ldt_64 + rm -f umip_ldt_32 + rm -f umip_ldt_16 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..ac28d240914 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/UMIP_README @@ -0,0 +1,32 @@ +A quick guide for UMIP testing + +* Use umip_test for a very basic test that exercises the instructions smsw, + str, sidt, sldt and sgdt from protected mode using the global descriptor + table. +* Use test2_32 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. +* DEPRECATED. Now UMIP is made to support only 32-bit builds of the kernel. + Use test2_64 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, 32 and 64 bits. Memory operands are always + 16-bit 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. +* Use umip_pf to verify that a page fault is correctly issued when UMIP- + emulated code tries to write in an invalid memory address of the user + space memory. +* Use umip_ldt to verify all the possible 32-bit address encodings in the + UMIP-emulated instructions. This includes all the ModRM, and SiB displacement + combinations. Furthermore, this test configure a Local Descriptor Table + whose segments have base addresses that are different from the __USER_DS + segment. +* Use umip_ldt_16 to verify all the possible 16-bit address encodings in the + UMIP-emulated instructions. This includes all the ModRM and displacement + combinations. Furthermore, this test configure a Local Descriptor Table + whose segments have base addresses that are different from the __USER_DS + segment. Also, the code segment is configured for 16-bit addresses. + diff --git a/meta-luv/recipes-core/umip/files/normal_pf.c b/meta-luv/recipes-core/umip/files/normal_pf.c new file mode 100644 index 00000000000..015a789620d --- /dev/null +++ b/meta-luv/recipes-core/umip/files/normal_pf.c @@ -0,0 +1,585 @@ +/* + * 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "umip_test_defs.h" + +static sig_atomic_t signal_code; +static sig_atomic_t got_signal; + +void 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_code[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 + errx(1, "ERROR: Received unexpected signal"); + + /* Save the signal code */ + signal_code = info->si_code; + /* + * Move to the next instruction. We have a cushion of + * several NOPs. Thus, we can safely move 8 positions + */ +#ifdef __x86_64__ + ctx->uc_mcontext.gregs[REG_RIP] += 8; +#else + ctx->uc_mcontext.gregs[REG_EIP] += 4; +#endif +} + +struct my_struct { + int a; + int b; + int c; +}; + +int test_normal_pf(void) +{ + unsigned long *val_bad = (unsigned long *)0x100000; + + asm volatile ("smsw %0\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n": "=m"(*val_bad)); + + if (!got_signal) { + pr_fail("Signal not received!\n"); + return 1; + } +#ifdef __x86_64__ + if (signal_code != SI_KERNEL) { + pr_fail("Signal code is not what we expect.\n"); + return 1; + } + pr_pass("A SEGV_MAPERR page fault was issued.\n"); + return 0; +#else + if (signal_code != SEGV_MAPERR) { + pr_fail("Signal code is not what we expect.\n"); + return 1; + } + pr_pass("A SEGV_MAPERR page fault was issued.\n"); + return 0; +#endif +} + +#define gen_test_lock_prefix_inst(name, inst) \ +static int __test_lock_prefix_##name(void) \ +{ \ + pr_info("Test %s with lock prefix\n", #name); \ + /* name (%eax) with the LOCK prefix */ \ + asm volatile(inst \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "nop\n"); \ + \ + if (signal_code != ILL_ILLOPN) { \ + pr_fail("Signal code is not what we expect.\n"); \ + signal_code = 0; \ + return 1; \ + } \ + pr_pass("An ILL_ILLOPN exception was issued.\n"); \ + signal_code = 0; \ + \ + return 0; \ +} + +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 int test_lock_prefix(void) +{ + int ret = 0; + ret = __test_lock_prefix_SMSW(); + if (ret) + return ret; + + ret = __test_lock_prefix_SIDT(); + if (ret) + return ret; + + ret = __test_lock_prefix_SGDT(); + if (ret) + return ret; + + ret = __test_lock_prefix_STR(); + if (ret) + return ret; + + ret = __test_lock_prefix_SLDT(); + + return ret; +} + +#define gen_test_register_operand_inst(name, inst) \ +static int __test_register_operand_##name(void) \ +{ \ + pr_info("Test %s with register operand\n", #name); \ + /* name (%eax) with the LOCK prefix */ \ + asm volatile(inst \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "nop\n"); \ + \ + if (signal_code != ILL_ILLOPN) { \ + pr_fail("Signal code is not what we expect.\n"); \ + signal_code = 0; \ + return 1; \ + } \ + pr_pass("An ILL_ILLOPN exception was issued.\n"); \ + signal_code = 0; \ + \ + return 0; \ +} + +gen_test_register_operand_inst(SIDT, ".byte 0xf, 0x1, 0xc8\n") +gen_test_register_operand_inst(SGDT, ".byte 0xf, 0x1, 0xc0\n") + +int test_register_operand(void) +{ + int ret; + + signal_code = 0; + ret = __test_register_operand_SGDT(); + if (ret) + return 1; + + ret = __test_register_operand_SIDT(); +} + +#ifdef __x86_64__ +int test_null_segment_selectors(void) +{ +} +#else +#define gen_test_null_segment_selector(inst, reg) \ +static int __test_null_segment_selector_##inst##_##reg(void) \ +{ \ + 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\n" \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "pop %ebx\n" \ + "pop %eax\n" \ + "pop %" #reg "\n"); \ + if (signal_code != SI_KERNEL) { \ + pr_fail("Signal code is not what we expect.\n"); \ + signal_code = 0; \ + return 1; \ + } \ + pr_pass("An ILL_ILLOPN exception was issued.\n"); \ + signal_code = 0; \ + \ + return 0; \ +} + +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) + +int test_null_segment_selectors(void) +{ + int ret; + + ret = __test_null_segment_selector_smsw_ds(); + if (ret) + return 1; + ret = __test_null_segment_selector_smsw_es(); + if (ret) + return 1; + ret = __test_null_segment_selector_smsw_fs(); + if (ret) + return 1; +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + ret = __test_null_segment_selector_smsw_gs(); + if (ret) + return 1; +#endif + + ret = __test_null_segment_selector_sidt_ds(); + if (ret) + return 1; + ret = __test_null_segment_selector_sidt_es(); + if (ret) + return 1; + ret = __test_null_segment_selector_sidt_fs(); + if (ret) + return 1; +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + ret = __test_null_segment_selector_sidt_gs(); + if (ret) + return 1; +#endif + + ret = __test_null_segment_selector_sgdt_ds(); + if (ret) + return 1; + ret = __test_null_segment_selector_sgdt_es(); + if (ret) + return 1; + ret = __test_null_segment_selector_sgdt_fs(); + if (ret) + return 1; +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + ret = __test_null_segment_selector_sgdt_gs(); + if (ret) + return 1; +#endif + + ret = __test_null_segment_selector_sldt_ds(); + if (ret) + return 1; + ret = __test_null_segment_selector_sldt_es(); + if (ret) + return 1; + ret = __test_null_segment_selector_sldt_fs(); + if (ret) + return 1; +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + ret = __test_null_segment_selector_sldt_gs(); + if (ret) + return 1; +#endif + + ret = __test_null_segment_selector_str_ds(); + if (ret) + return 1; + ret = __test_null_segment_selector_str_es(); + if (ret) + return 1; + ret = __test_null_segment_selector_str_fs(); + if (ret) + return 1; +#ifdef TEST_GS /* TODO: Meddling with gs breaks libc */ + ret = __test_null_segment_selector_str_gs(); + if (ret) + return 1; +#endif + return 0; +} +#endif + +#ifdef __x86_64__ +int 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("Failed to install stack semgnet [%d].\n", ret); + return ret; + } + + return 0; +} + +#define gen_test_addresses_outside_segment(inst, sel) \ +int __test_addresses_outside_segment_##inst##_##sel(void) \ +{ \ + int ret; \ + unsigned short seg_sel; \ + \ + 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\n" \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "nop\n" \ + "pop %%ebx\n" \ + "pop %%eax\n" \ + "pop %%" #sel "\n" \ + : \ + :"m" (seg_sel)); \ + \ + if (signal_code != SI_KERNEL) { \ + pr_fail("Signal code is not what we expect.\n"); \ + signal_code = 0; \ + return 1; \ + } \ + pr_pass("An ILL_ILLOPN exception was issued.\n"); \ + signal_code = 0; \ + \ + return 0; \ +} + +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) + +int test_addresses_outside_segment(void) +{ + int ret; + + ret = setup_data_segments(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_smsw_ds(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_str_ds(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sgdt_ds(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sidt_ds(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sldt_ds(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_smsw_es(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_str_es(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sgdt_es(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sidt_es(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sldt_es(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_smsw_fs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_str_fs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sgdt_fs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sidt_fs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sldt_fs(); + if (ret) + return 1; + +#ifdef TEST_GS + ret = __test_addresses_outside_segment_smsw_gs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_str_gs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sgdt_gs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sidt_gs(); + if (ret) + return 1; + + ret = __test_addresses_outside_segment_sldt_gs(); + if (ret) + return 1; +#endif +} +#endif + +int main (void) +{ + struct sigaction action; + int ret; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("Could not set the signal handler for SIGSEGV!\n"); + exit(1); + } + + if (sigaction(SIGILL, &action, NULL) < 0) { + pr_error("Could not set the signal handler SIGILL!\n"); + exit(1); + } + + ret = test_normal_pf(); + if (ret) + return 1; + + ret = test_lock_prefix(); + if (ret) + return 1; + + ret = test_register_operand(); + if (ret) + return 1; + + ret = test_null_segment_selectors(); + if (ret) + return 1; + + test_addresses_outside_segment(); + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("Could not remove signal SIGSEGV handler!\n"); + return 1; + } + + if (sigaction(SIGILL, &action, NULL) < 0) { + pr_error("Could not remove signal SIGILL handler!\n"); + return 1; + } + + return ret; +} 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..97df9ca74f7 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_ldt_16.c @@ -0,0 +1,366 @@ +/* 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_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[]; +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)) + +static sig_atomic_t got_signal; + +void handler(int signum, siginfo_t *info, void *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_code[0x%p]\n", info->si_addr); + if (signum != SIGSEGV) + pr_error("Received unexpected signal"); + else + got_signal = signum; + 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"); + + pr_fail("Whoa! I got a SIGSEGV! Something went wrong!\n"); + exit(1); +} + +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("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("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("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_es, 0x66, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error("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_es, 0x55, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error("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 = &handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("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("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("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("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("Failed to install 16-bit code segment [%d].\n", ret); + goto err_out; + } + + if (setup_data_segments()) { + pr_error("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 %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 interim 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 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 %5, %%esi\n\t" + "mov %6, %%edi\n\t" + /* + *ljmp only takes constants. Instead use retf, which takes + * instruction pointer and code segment selector from the stack + */ + "push %7\n\t" + "push %8\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" + : + :"m"(test_ds_16), "m"(test_es_16), "m"(test_fs_16), "m"(test_gs_16), + "m"(interim_ss), "m"(test_ss_16), "m"(test_cs_16), "m"(interim_cs), "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("Could not remove signal handler!"); + exit(1); + } + + printf("Exiting...\n"); + return 0; +err_out: + pr_error("Could not run tests\n"); + 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..ac0d731a3bc --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_ldt_32.c @@ -0,0 +1,279 @@ +/* Test cases for UMIP */ +/* Copyright Intel Corporation 2017 */ + +#define _GNU_SOURCE +#include +#include +#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[]; +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)) + +static sig_atomic_t got_signal; + +void handler(int signum, siginfo_t *info, void *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_code[0x%p]\n", info->si_addr); + if (signum != SIGSEGV) + pr_error("Received unexpected signal"); + else + got_signal = signum; + 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"); + + pr_fail("Whoa! I got a SIGSEGV! Something went wrong!\n"); + exit(1); +} + +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("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("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("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_es, 0x66, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error("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_es, 0x55, SEGMENT_SIZE); + + ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); + if (ret) { + pr_error("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 = &handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("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("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("Failed to install code segment [%d].\n", ret); + goto err_out; + } + + if (setup_data_segments()) { + pr_error("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("Could not remove signal handler!"); + exit(1); + } + + pr_info("Exiting...\n"); + + return 0; +err_out: + pr_error("Could not run tests\n"); + 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..d8d21e02b76 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_ldt_64.c @@ -0,0 +1,189 @@ +/* Test cases for UMIP */ +/* Copyright Intel Corporation 2017 */ + +#include +#include +#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[]; +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)) + +static sig_atomic_t got_signal; + +void handler(int signum, siginfo_t *info, void *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_code[0x%p]\n", info->si_addr); + if (signum != SIGSEGV) + pr_error("Received unexpected signal"); + else + got_signal = signum; + 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"); + + pr_fail("Whoa! I got a SIGSEGV! Something went wrong!\n"); + exit(1); +} + +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; +} + +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 = &handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("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("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" + /* set new data segment */ + /* jump to test code */ + "call *%2\n\t" + /* After running tests, we return here */ + "finish_testing:\n\t" + /* restore everything */ + "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"(test_fs), "m"(test_gs), "m"(code) + ); + + 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); + + 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("Could not remove signal handler!"); + exit(1); + } + printf("Exiting...\n"); + + return 0; +err_out: + pr_error("Could not run tests\n"); + return 1; +}; + diff --git a/meta-luv/recipes-core/umip/files/umip_test.c b/meta-luv/recipes-core/umip/files/umip_test.c new file mode 100644 index 00000000000..cc2015beba1 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test.c @@ -0,0 +1,253 @@ +/* + * tests for Intel User-Mode Execution Prevention + * + * GPLv2 + */ + +#define _GNU_SOURCE +#include +#include +#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 + +static sig_atomic_t got_signal; + +static void handler(int signum, siginfo_t *info, void *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_code[0x%p]\n", info->si_addr); + if (signum != SIGSEGV) + errx(1, "ERROR: Received unexpected signal"); + else + got_signal = signum; + 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"); + +#ifdef __x86_64__ + pr_pass("I got a SIGSEGV. UMIP not emulated in 64-bit\n"); +#else + pr_fail("FAIL: Whoa! I got a SIGSEGV. This is an error!\n"); +#endif + exit(1); +} + +static void call_sgdt() +{ + unsigned char val[GDTR_LEN]; + unsigned long base = INIT_VAL(89898989); + unsigned short limit = 0x3d3d; + int i; + + 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" : "=m" (val)); + + limit = val[1] << 8 | val[0]; + pr_info("GDT Limit [0x%04x]\n", limit); + + if (limit == expected_gdt.limit) + pr_pass("Expected limit value\n"); + else + pr_fail("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("Expected base value\n"); + else + pr_fail("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; + + 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" : "=m" (val)); + + limit = val[1] << 8 | val[0]; + pr_info("IDT Limit [0x%04x]\n", limit); + + if (limit == expected_idt.limit) + pr_pass("Expected limit value\n"); + else + pr_fail("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("Expected base value\n"); + else + pr_fail("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; + + pr_info("Will issue SLDT and save at [%p]\n", &val); + asm volatile("sldt %0" : "=m" (val)); + + 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 && + (val & ~mask) == (init_val & ~mask)) + pr_pass("Obtained expected value\n"); + else + pr_fail("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; + + pr_info("Will issue SMSW and save at [%p]\n", &val); + asm volatile("smsw %0" : "=m" (val)); + + 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 && + (val & ~mask) == (init_val & ~mask)) + pr_pass("Obtained expected value\n"); + else + pr_fail("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; +#if __x86_64__ + unsigned long val64 = 0xa3a3a3a3a3a3a3a3; + + pr_info("Will issue STR and save at m64[0x%p]\n", &val64); + asm volatile("str %0" : "=m" (val64)); + pr_info("SS for TSS[0x%016lx]\n", val64); + + /* All 64 bits are written */ + if (val64 == expected_tr) + pr_pass("Obtained 64-bit expected value\n"); + else + pr_fail("Obtained 64-bit unexpected value\n"); +#endif + + pr_info("Will issue STR and save at m32[0x%p]\n", &val32); + asm volatile("str %0" : "=m" (val32)); + 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 && + (val32 & ~0xffff) == (init_val32 & ~0xffff)) + pr_pass("Obtained 32-bit expected value\n"); + else + pr_fail("Obtained 32-bit unexpected value\n"); + + pr_info("Will issue STR and save at m16[0x%p]\n", &val16); + asm volatile("str %0" : "=m" (val16)); + 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 && + (val16 & ~0xffff) == (init_val16 & ~0xffff)) + pr_pass("Obtained 16-bit expected value\n"); + else + pr_fail("Obtained 16-bit unexpected value\n"); + +} + +int main(void) +{ + struct sigaction action; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("Could not set the signal handler!"); + exit(1); + } + + call_sgdt(); + call_sidt(); + call_sldt(); + call_smsw(); + call_str(); + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("Could not remove signal handler!"); + return 1; + } + + return 0; +} diff --git a/meta-luv/recipes-core/umip/files/umip_test2.c b/meta-luv/recipes-core/umip/files/umip_test2.c new file mode 100644 index 00000000000..af020b783f5 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test2.c @@ -0,0 +1,334 @@ +#include +#include +#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" +#else +#define PUSH(reg) "push %%e"reg"\n" +#define POP(reg) "pop %%e"reg"\n" +#endif + +#define INSNreg16(insn, reg, aux) \ + PUSH(aux) \ + PUSH(reg) \ + insn" %%"reg"\n" \ + "mov %%"reg", %%"aux"\n" \ + POP(reg) \ + "mov %%"aux", %0\n" \ + POP(aux) + +#define INSNreg32(insn, reg, aux) \ + PUSH(aux) \ + PUSH(reg) \ + insn" %%e"reg"\n" \ + "mov %%e"reg", %%e"aux"\n" \ + POP(reg) \ + "movl %%e"aux", %0\n" \ + POP(aux) + +#define INSNreg64(insn, reg, aux) \ + "push %%"aux"\n" \ + "push %%"reg"\n" \ + insn" %%"reg"\n" \ + "mov %%"reg", %%"aux"\n" \ + "pop %%"reg"\n" \ + "mov %%"aux", %0\n" \ + "pop %%"aux"\n" + +#define CHECK_INSN(op_size, insn, reg, val, aux, init, exp) \ + do { \ + val = init; \ + mask = get_mask(op_size); \ + if (!mask) \ + return -1; \ + asm volatile(INSNreg##op_size(insn, reg, aux) : "=m" (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) == (exp & mask)) && ((exp & ~mask) == (exp & ~mask))) \ + pr_pass(" On %s-bit '%s %s'! Got [0x%lx] Exp[0x%lx]\n", \ + #op_size, insn, reg, val, exp); \ + else { \ + pr_fail("On %s-bit '%s %s'! Got[0x%lx] Exp[0x%lx]\n", \ + #op_size, insn, reg, val, exp); \ + return -1; \ + } \ + } while(0); + +#define CHECK_ALLreg32(insn, val, init, exp) \ + CHECK_INSN(16, insn, "ax", val, "bx", init, exp); \ + CHECK_INSN(16, insn, "cx", val, "ax", init, exp); \ + CHECK_INSN(16, insn, "dx", val, "ax", init, exp); \ + CHECK_INSN(16, insn, "bx", val, "ax", init, exp); \ + CHECK_INSN(16, insn, "bp", val, "ax", init, exp); \ + CHECK_INSN(16, insn, "si", val, "ax", init, exp); \ + CHECK_INSN(16, insn, "di", val, "ax", init, exp); \ + CHECK_INSN(32, insn, "ax", val, "bx", init, exp); \ + CHECK_INSN(32, insn, "cx", val, "ax", init, exp); \ + CHECK_INSN(32, insn, "dx", val, "ax", init ,exp); \ + CHECK_INSN(32, insn, "bx", val, "ax", init ,exp); \ + CHECK_INSN(32, insn, "bp", val, "ax", init, exp);\ + CHECK_INSN(32, insn, "si", val, "ax", init, exp); \ + CHECK_INSN(32, insn, "di", val, "ax", init, exp); \ + +#define CHECK_ALLreg64(insn, val, init, exp) \ + CHECK_INSN(64, insn, "rax", val, "rbx", init, exp); \ + CHECK_INSN(64, insn, "rcx", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "rdx", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "rbx", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "rbp", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "rsi", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "rdi", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r8", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r9", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r10", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r11", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r12", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r13", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r14", val, "rax", init, exp); \ + CHECK_INSN(64, insn, "r15", val, "rax", 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, disp) \ + "push %%rax\n" /* rax used to copy values around. Make a copy */ \ + "mov %0, %%rax\n" /* Init our variable. Split into two instructions */ \ + "mov %%rax, "disp"(%%rsp)\n" \ + "mov %%"reg", %%rax\n" /* make a backup of register under test */ \ + "mov %%rsp, %%"reg"\n" /* move rsp to our register under test */ \ + insn" "disp"(%%"reg")\n" /* execute our instruction */ \ + "push "disp"(%%"reg")\n" /* save result to stack */ \ + "mov %%rax, %%"reg"\n" /* restore register under test */ \ + "pop %1\n" /* copy result to our variable */ \ + "pop %%rax\n" /* restore rax */ +#else +#define INSNmem(insn, reg, disp) \ + "push %%eax\n" /* eax used to copy values around. Make a copy */ \ + "mov %0, %%eax\n" /* Init our variable. Split into two instructions */ \ + "mov %%eax, "disp"(%%esp)\n" \ + "mov %%"reg", %%eax\n" /* make a backup of register under test */ \ + "mov %%esp, %%"reg"\n" /* move esp to our register under test */ \ + insn" "disp"(%%"reg")\n" /* execute our instruction */ \ + "push "disp"(%%"reg")\n" /* save result to stack */ \ + "mov %%eax, %%"reg"\n" /* restore register under test */ \ + "pop %1\n" /* copy result to our variable */ \ + "pop %%eax\n" /* restore eax */ +#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) INSNmem(insn, reg, "-0x80") +#define INSNmemdisp32(insn, reg) INSNmem(insn, reg, "-0x1000") + +#define CHECK_INSNmemdisp(INSNmacro, insn, reg, val, init, exp) \ + val = init; \ + /* Memory operands are always treated as 16-bit locations */ \ + mask = get_mask(16); \ + if (!mask) \ + return -1; \ + asm volatile(INSNmacro(insn, reg) : "=m" (val): "m"(val) : "%rax"); \ + /* \ + * 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("On '%s %s(%s)'! Got [0x%lx] Exp[0x%lx]\n", \ + insn, #INSNmacro, reg, val, exp); \ + else { \ + pr_fail("On '%s %s(%s)'! Got[0x%lx] Exp[0x%lx]\n", \ + insn, #INSNmacro, reg, val, exp); \ + return -1; \ + } + +#define CHECK_INSNmem(insn, reg, val, init, exp) \ + CHECK_INSNmemdisp(INSNmemdisp8, insn, reg, val, init, exp) \ + CHECK_INSNmemdisp(INSNmemdisp32, insn, reg, val, init, exp) + +#if __x86_64__ +#define CHECK_ALLmem(insn, val, init, exp) \ + CHECK_INSNmem(insn, "rax", val, init, exp) \ + CHECK_INSNmem(insn, "rcx", val, init, exp) \ + CHECK_INSNmem(insn, "rdx", val, init, exp) \ + CHECK_INSNmem(insn, "rbp", val, init, exp) \ + CHECK_INSNmem(insn, "rsi", val, init, exp) \ + CHECK_INSNmem(insn, "rdi", val, init, exp) \ + CHECK_INSNmem(insn, "r8", val, init, exp) \ + CHECK_INSNmem(insn, "r9", val, init, exp) \ + CHECK_INSNmem(insn, "r10", val, init, exp) \ + CHECK_INSNmem(insn, "r11", val, init, exp) \ + CHECK_INSNmem(insn, "r12", val, init, exp) \ + CHECK_INSNmem(insn, "r13", val, init, exp) \ + CHECK_INSNmem(insn, "r14", val, init, exp) \ + CHECK_INSNmem(insn, "r15", val, init, exp) +#else +#define CHECK_ALLmem(insn, val, init, exp) \ + CHECK_INSNmem(insn, "eax", val, init, exp) \ + CHECK_INSNmem(insn, "ecx", val, init, exp) \ + CHECK_INSNmem(insn, "edx", val, init, exp) \ + CHECK_INSNmem(insn, "ebp", val, init, exp) \ + CHECK_INSNmem(insn, "esi", val, init, exp) \ + CHECK_INSNmem(insn, "edi", val, init, exp) +#endif + +#define INIT_SS INIT_VAL(13131313) +#define INIT_MSW INIT_VAL(14141414) +#define INIT_LDTS INIT_VAL(15151515) + +static sig_atomic_t got_signal; + +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("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 short mask = 0xffff; + + pr_info("====Checking STR. Expected value: [0x%x]====\n", expected_tr); + pr_info("==Tests for register operands==\n"); + pr_info("Value should be saved at [0x%p]\n", &val); + 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]\n", &val); + 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 short mask = 0xffff; + + pr_info("====Checking SMSW. Expected value: [0x%x]====\n", expected_msw); + pr_info("==Tests for register operands==\n"); + pr_info("Value should be saved at [0x%p]\n", &val); + 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]\n", &val); + 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 short mask = 0xffff; + + pr_info("====Checking SLDT. Expected value: [0x%x]====\n", expected_ldt); + pr_info("==Tests for register operands==\n"); + pr_info("Value should be saved at [0x%p]\n", &val); + 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]\n", &val); + CHECK_ALLmem("sldt", val, INIT_LDTS, (unsigned long)expected_ldt); + /* TODO: check with addressing using SIB byte */ + return 0; +} + +static void handler(int signum, siginfo_t *info, void *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_code[0x%p]\n", info->si_addr); + if (signum != SIGSEGV) + pr_error("Received unexpected signal"); + else + got_signal = signum; + 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"); + +#ifdef __x86_64__ + pr_pass("I got a SIGSEGV. UMIP not emulated in 64-bit\n"); +#else + pr_fail("FAIL: Whoa! I got a SIGSEGV. This is an error!\n"); +#endif + exit(1); +} + +int main (void) +{ + int ret_str, ret_smsw, ret_sldt; + struct sigaction action; + + PRINT_BITNESS; + + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &handler; + action.sa_flags = SA_SIGINFO; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGSEGV, &action, NULL) < 0) { + pr_error("Could not set the signal handler!"); + exit(1); + } + + pr_info("***Starting tests***\n"); + ret_str = test_str(); + ret_smsw = test_smsw(); + ret_sldt = test_sldt(); + if (ret_str || ret_smsw || ret_sldt) + pr_fail("***Test completed with errors str[%d] smsw[%d] sldt[%d]\n", + ret_str, ret_smsw, ret_sldt); + else + pr_pass("***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("Could not remove signal handler!"); + return 1; + } + + 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..adce05b1824 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_defs.h @@ -0,0 +1,50 @@ +#ifndef _UMIP_TEST_DEFS_H +#define _UMIP_TEST_DEFS_H +#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(...) printf(TEST_PASS __VA_ARGS__) +#define pr_fail(...) printf(TEST_FAIL __VA_ARGS__) +#define pr_info(...) printf(TEST_INFO __VA_ARGS__) +#define pr_error(...) printf(TEST_ERROR __VA_ARGS__) + +#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 0x33 +#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 + +struct table_desc { + unsigned short limit; + unsigned long base; +} __attribute__((packed)); + +static const unsigned short expected_msw = EXPECTED_SMSW; +static const unsigned short expected_ldt = EXPECTED_SLDT; +static const unsigned short 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 +}; + +#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..2d60b138850 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_gen_16.py @@ -0,0 +1,411 @@ +""" 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""" + +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 + +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): + # TODO: Use an enum here + if (inst.result_bytes == 2): + checkcode = "\tgot = *(unsigned short *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tprintf(\"%s " + comment + ". Got:[0x%x]Exp[0x%x]\\n\",\n" + checkcode += "\t got==expected ? TEST_PASS : TEST_FAIL, got, expected);\n" + elif (inst.result_bytes == 6): + checkcode = "\tgot = (struct table_desc *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tprintf(\"%s " + comment + ". Got:Base[0x%lx]Limit[0x%x]ExpBase[0x%lx]Limit[0x%x]\\n\",\n" + checkcode += "\t ((got->base == expected->base) && (got->limit == expected->limit)) ? TEST_PASS : TEST_FAIL, got->base, got->limit, expected->base, expected->limit);\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) + + 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) + + 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 += "unsigned char data[SEGMENT_SIZE];\n" + header_info += "unsigned char data_es[SEGMENT_SIZE];\n" + header_info += "unsigned char data_fs[SEGMENT_SIZE];\n" + header_info += "unsigned char data_gs[SEGMENT_SIZE];\n" + header_info += "unsigned char stack_32[SEGMENT_SIZE];\n" + header_info += "unsigned char stack[SEGMENT_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" + + 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 write_test_files(): + 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..181a666ae46 --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_gen_32.py @@ -0,0 +1,648 @@ +""" 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""" + +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 + +#expected values +EXPECTED_SMSW = 0x33 +EXPECTED_SLDT = 0x0 +EXPECTED_STR = 0x0 +EXPECTED_GDT_BASE = 0xfffe0000 +EXPECTED_GDT_LIMIT = 0x0 +EXPECTED_IDT_BASE = 0xffff0000 +EXPECTED_IDT_LIMIT = 0x0 + +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): + # TODO: Use an enum here + if (inst.result_bytes == 2): + checkcode = "\tgot = *(unsigned short *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tprintf(\"%s " + comment + ". Got:[0x%x]Exp[0x%x]\\n\",\n" + checkcode += "\t got==expected ? TEST_PASS : TEST_FAIL, got, expected);\n" + elif (inst.result_bytes == 6): + checkcode = "\tgot = (struct table_desc *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tprintf(\"%s " + comment + ". Got:Base[0x%lx]Limit[0x%x]ExpBase[0x%lx]Limit[0x%x]\\n\",\n" + checkcode += "\t ((got->base == expected->base) && (got->limit == expected->limit)) ? TEST_PASS : TEST_FAIL, got->base, got->limit, expected->base, expected->limit);\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) + + 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) + + 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 += "unsigned char data[SEGMENT_SIZE];\n" + header_info += "unsigned char data_es[SEGMENT_SIZE];\n" + header_info += "unsigned char data_fs[SEGMENT_SIZE];\n" + header_info += "unsigned char data_gs[SEGMENT_SIZE];\n" + header_info += "unsigned char stack[SEGMENT_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" + + 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 write_test_files(): + 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..795fc12a29e --- /dev/null +++ b/meta-luv/recipes-core/umip/files/umip_test_gen_64.py @@ -0,0 +1,651 @@ +""" 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""" + +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 + +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): + # TODO: Use an enum here + if (inst.result_bytes == 2): + checkcode = "\tgot = *(unsigned short *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tprintf(\"%s " + comment + ". Got:[0x%x]Exp[0x%x]\\n\",\n" + checkcode += "\t got==expected ? TEST_PASS : TEST_FAIL, got, expected);\n" + elif (inst.result_bytes == 6): + checkcode = "\tgot = (struct table_desc *)(" + segment_chk_str +" + " + str(my_hex(address)) + ");\n" + checkcode += "\tprintf(\"%s " + comment + ". Got:Base[0x%lx]Limit[0x%x]ExpBase[0x%lx]Limit[0x%x]\\n\",\n" + checkcode += "\t ((got->base == expected->base) && (got->limit == expected->limit)) ? TEST_PASS : TEST_FAIL, got->base, got->limit, expected->base, expected->limit);\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) + + 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) + + 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 += "#define SEGMENT_SIZE " + str(SEGMENT_SIZE) + "\n" + header_info += "#define CODE_MEM_SIZE " + str(CODE_MEM_SIZE) + "\n" + header_info += "\n" + header_info += "unsigned char data_fs[SEGMENT_SIZE];\n" + header_info += "unsigned char data_gs[SEGMENT_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_64.h\"\n\n" + check_code += "#include \"umip_test_defs.h\"\n\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 write_test_files(): + 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/umip-tests_0.1.bb b/meta-luv/recipes-core/umip/umip-tests_0.1.bb new file mode 100644 index 00000000000..0b41db5b23a --- /dev/null +++ b/meta-luv/recipes-core/umip/umip-tests_0.1.bb @@ -0,0 +1,60 @@ +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_test.c \ + file://umip_test2.c \ + file://normal_pf.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://UMIP_README \ + " + + +do_configure[noexec] = "1" + +EXTRA_OEMAKE += " ${TARGET_ARCH}" + +S = "${WORKDIR}" + +do_compile() { + 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_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_pf_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test2_64 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_64 ${D}${bindir} + fi + if [ "${TARGET_ARCH}" = "i586" ]; then + install -m 755 ${WORKDIR}/umip_test_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_pf_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test2_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_16 ${D}${bindir} + fi + if [ "${TARGET_ARCH}" = "i686" ]; then + install -m 755 ${WORKDIR}/umip_test_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_pf_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_test2_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_32 ${D}${bindir} + install -m 755 ${WORKDIR}/umip_ldt_16 ${D}${bindir} + fi + +} + + 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/0001-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0001-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch new file mode 100644 index 00000000000..7efc6d9f785 --- /dev/null +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0001-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch @@ -0,0 +1,116 @@ +From 1a0461d77254759e3990e06171f9fdcfdbad3e38 Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Tue, 9 Aug 2016 12:48:24 -0700 +Subject: [PATCH 10/11] 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 catches 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 INT 0x80. + +The instructions protected by UMIP are executed in representative use +cases: + a) the memory address of the result is given in the form of a displacement + from the base of the data segment + b) the memory address of the result is given in a general purpose register + c) the result is stored directly in a general purpose register. + +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. + +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 | 39 ++++++++++++++++++++++++++- + 1 file changed, 38 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..377b773 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" ++ "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" ++ "int $0x80\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[], umip[]; + + /* Returns false if the test was skipped. */ + static bool do_test(struct vm86plus_struct *v86, unsigned long eip, +@@ -218,6 +234,27 @@ 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_test(&v86, umip - vmcode, VM86_INTx, 0x80, "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:\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 SMSW via register operands:\n"); ++ printf("[INFO]\tSMSW:[0x%04x]\n", *(unsigned short *)(addr + 2080)); ++ + /* 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/0002-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0002-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch new file mode 100644 index 00000000000..094e96bb777 --- /dev/null +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test/0002-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch @@ -0,0 +1,394 @@ +From a47399192fed6e0c9cb8ae3a3af1bb158636e0fb Mon Sep 17 00:00:00 2001 +From: Ricardo Neri +Date: Mon, 23 Jan 2017 18:31:35 -0800 +Subject: [PATCH 11/11] 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 | 342 +++++++++++++++++++++++++- + 1 file changed, 338 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c +index 377b773..c7bf946 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" + "int $0x80\n\t" + ".size vmcode, . - vmcode\n\t" + "end_vmcode:\n\t" +@@ -244,7 +390,7 @@ int main(void) + 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:\n"); ++ 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), +@@ -252,8 +398,196 @@ int main(void) + printf("[INFO]\tSGDT: limit[0x%04x]base[0x%08lx]\n", + *(unsigned short *)(addr + 2074), + *(unsigned long *)(addr + 2076)); +- printf("[INFO]\tResults of SMSW via register operands:\n"); ++ ++ 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.9.bb b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.9.bb index d47413f7a37..265cacfcc9e 100644 --- a/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.9.bb +++ b/meta-luv/recipes-kernel/linux/linux-yocto-efi-test_4.9.bb @@ -69,6 +69,8 @@ SRC_URI += "file://0001-Add-function-to-fixup-page-faults-in-BOOT_SERVICES_-.pat file://0002-efi-allow-efi_mem_desc_lookup-find-EFI_BOOT_SERVICES.patch \ file://0003-x86-efi-Fixup-faults-from-UEFI-firmware.patch \ file://0004-x86-efi-Introduce-EFI_BOOT_SERVICES_WARN.patch \ + file://0001-selftests-x86-Add-tests-for-User-Mode-Instruction-Pr.patch \ + file://0002-selftests-x86-Add-more-tests-for-User-Mode-Instructi.patch \ " # These patches are under discussion on ML SRC_URI += "file://0001-serial-SPCR-check-bit-width-for-the-16550-UART.patch \ 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 }