This adds support for AMD's SVME instructions. Built and tested on i686-pc-linux-gnu and x86_64-unknown-linux-gnu. Jan gas/ 2005-06-16 Jan Beulich * config/tc-i386.h (CpuSVME): New. (CpuUnknownFlags): Include CpuSVME. * config/tc-i386.c (cpu_arch): Add .pacifica and .svme. Add opteron as alias of sledgehammer. (md_assemble): Include invlpga in the check for insns with two source operands. (process_operands): Include SVME insns in the check for ignored segment overrides. Adjust diagnostic. (i386_index_check): Special-case SVME insns with memory operands. gas/testsuite/ 2005-06-16 Jan Beulich * gas/i386/svme.d: New. * gas/i386/svme.s: New. * gas/i386/svme64.d: New. * gas/i386/i386.exp: Run new tests. include/opcode/ 2005-06-16 Jan Beulich * i386.h (i386_optab): Add new insns. opcodes/ 2005-06-16 Jan Beulich * i386-dis.c (SVME_Fixup): New. (grps): Use it for the lidt entry. (PNI_Fixup): Call OP_M rather than OP_E. (INVLPG_Fixup): Likewise. --- /home/jbeulich/src/binutils/mainline/2005-06-16/gas/config/tc-i386.c 2005-06-08 14:50:49.000000000 +0200 +++ 2005-06-16/gas/config/tc-i386.c 2005-06-16 15:06:59.993204152 +0200 @@ -429,12 +429,15 @@ static const arch_entry cpu_arch[] = { {"k6_2", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow }, {"athlon", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA }, {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 }, + {"opteron", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 }, {".mmx", CpuMMX }, {".sse", CpuMMX|CpuMMX2|CpuSSE }, {".sse2", CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 }, {".3dnow", CpuMMX|Cpu3dnow }, {".3dnowa", CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA }, {".padlock", CpuPadLock }, + {".pacifica", CpuSVME }, + {".svme", CpuSVME }, {NULL, 0 } }; @@ -1399,6 +1402,7 @@ md_assemble (line) have two immediate operands. */ if (intel_syntax && i.operands > 1 && (strcmp (mnemonic, "bound") != 0) + && (strcmp (mnemonic, "invlpga") != 0) && !((i.types[0] & Imm) && (i.types[1] & Imm))) swap_operands (); @@ -2830,8 +2834,10 @@ process_operands () default_seg = &ds; } - if (i.tm.base_opcode == 0x8d /* lea */ && i.seg[0] && !quiet_warnings) - as_warn (_("segment override on `lea' is ineffectual")); + if ((i.tm.base_opcode == 0x8d /* lea */ + || (i.tm.cpu_flags & CpuSVME)) + && i.seg[0] && !quiet_warnings) + as_warn (_("segment override on `%s' is ineffectual"), i.tm.name); /* If a segment was explicitly specified, and the specified segment is not the default, use an opcode prefix to select it. If we @@ -4172,7 +4178,30 @@ i386_index_check (operand_string) tryprefix: #endif ok = 1; - if (flag_code == CODE_64BIT) + if ((current_templates->start->cpu_flags & CpuSVME) + && current_templates->end[-1].operand_types[0] == AnyMem) + { + /* Memory operands of SVME insns are special in that they only allow + rAX as their memory address and ignore any segment override. */ + unsigned RegXX; + + /* SKINIT is even more restrictive: it always requires EAX. */ + if (strcmp (current_templates->start->name, "skinit") == 0) + RegXX = Reg32; + else if (flag_code == CODE_64BIT) + RegXX = i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32; + else + RegXX = (flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0) + ? Reg16 + : Reg32; + if (!i.base_reg + || !(i.base_reg->reg_type & Acc) + || !(i.base_reg->reg_type & RegXX) + || i.index_reg + || (i.types[0] & Disp)) + ok = 0; + } + else if (flag_code == CODE_64BIT) { unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32); --- /home/jbeulich/src/binutils/mainline/2005-06-16/gas/config/tc-i386.h 2005-06-08 14:50:49.000000000 +0200 +++ 2005-06-16/gas/config/tc-i386.h 2005-06-16 15:06:59.996203696 +0200 @@ -184,13 +184,16 @@ typedef struct #define Cpu3dnowA 0x10000 /* 3dnow!Extensions support required */ #define CpuPNI 0x20000 /* Prescott New Instructions required */ #define CpuPadLock 0x40000 /* VIA PadLock required */ +#define CpuSVME 0x80000 /* AMD Secure Virtual Machine Ext-s required */ /* These flags are set by gas depending on the flag_code. */ #define Cpu64 0x4000000 /* 64bit support required */ #define CpuNo64 0x8000000 /* Not supported in the 64bit mode */ /* The default value for unknown CPUs - enable all features to avoid problems. */ -#define CpuUnknownFlags (Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuSledgehammer|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuPNI|Cpu3dnow|Cpu3dnowA|CpuK6|CpuAthlon|CpuPadLock) +#define CpuUnknownFlags (Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 \ + |CpuP4|CpuSledgehammer|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuPNI \ + |Cpu3dnow|Cpu3dnowA|CpuK6|CpuAthlon|CpuPadLock|CpuSVME) /* the bits in opcode_modifier are used to generate the final opcode from the base_opcode. These bits also are used to detect alternate forms of --- /home/jbeulich/src/binutils/mainline/2005-06-16/gas/testsuite/gas/i386/i386.exp 2005-05-09 08:31:39.000000000 +0200 +++ 2005-06-16/gas/testsuite/gas/i386/i386.exp 2005-06-16 15:09:06.599957000 +0200 @@ -74,6 +74,7 @@ if [expr ([istarget "i*86-*-*"] || [ist run_dump_test "padlock" run_dump_test "crx" run_list_test "cr-err" "" + run_dump_test "svme" # These tests require support for 8 and 16 bit relocs, # so we only run them for ELF and COFF targets. @@ -128,6 +129,7 @@ if [expr ([istarget "i*86-*-*"] || [ista run_list_test "x86-64-segment" "-al" run_list_test "x86-64-inval-seg" "-al" run_dump_test "x86-64-branch" + run_dump_test "svme64" # For ELF targets verify that @unwind works. if { ([istarget "*-*-elf*"] || [istarget "*-*-linux*"] --- /home/jbeulich/src/binutils/mainline/2005-06-16/gas/testsuite/gas/i386/svme.d 1970-01-01 01:00:00.000000000 +0100 +++ 2005-06-16/gas/testsuite/gas/i386/svme.d 2005-06-14 12:53:59.000000000 +0200 @@ -0,0 +1,29 @@ +#objdump: -dw +#name: 32-bit SVME + +.*: +file format .* + +Disassembly of section .text: + +0+000 : +[ ]*[0-9a-f]+:[ ]+0f 01 dd[ ]+clgi[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 df[ ]+invlpga[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 de[ ]+skinit[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 dc[ ]+stgi[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 da[ ]+vmload[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d9[ ]+vmmcall[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d8[ ]+vmrun[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 db[ ]+vmsave[ ]* +[0-9a-f]+ : +[ ]*[0-9a-f]+:[ ]+0f 01 de[ ]+skinit[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 df[ ]+invlpga[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 da[ ]+vmload[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d8[ ]+vmrun[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 db[ ]+vmsave[ ]* +[0-9a-f]+ : +[ ]*[0-9a-f]+:[ ]+0f 01 de[ ]+skinit[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 df[ ]+invlpga[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 da[ ]+vmload[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d8[ ]+vmrun[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 db[ ]+vmsave[ ]* +#pass --- /home/jbeulich/src/binutils/mainline/2005-06-16/gas/testsuite/gas/i386/svme.s 1970-01-01 01:00:00.000000000 +0100 +++ 2005-06-16/gas/testsuite/gas/i386/svme.s 2005-06-14 12:38:02.000000000 +0200 @@ -0,0 +1,36 @@ + .text +common: + clgi + invlpga + skinit + stgi + vmload + vmmcall + vmrun + vmsave + +.macro do_args arg1, arg2 + invlpga \arg1, \arg2 + vmload \arg1 + vmrun \arg1 + vmsave \arg1 +.endm + +.ifdef __amd64__ +att64: + do_args (%rax), %ecx +.endif +att32: + skinit (%eax) + do_args (%eax), %ecx + +.intel_syntax noprefix +.ifdef __amd64__ +intel64: + do_args [rax], ecx +.endif +intel32: + skinit [eax] + do_args [eax], ecx + + .p2align 4,0 --- /home/jbeulich/src/binutils/mainline/2005-06-16/gas/testsuite/gas/i386/svme64.d 1970-01-01 01:00:00.000000000 +0100 +++ 2005-06-16/gas/testsuite/gas/i386/svme64.d 2005-06-15 15:41:58.000000000 +0200 @@ -0,0 +1,41 @@ +#as: --defsym __amd64__=1 +#objdump: -dw +#name: 64-bit SVME +#source: svme.s + +.*: +file format .* + +Disassembly of section .text: + +0+000 : +[ ]*[0-9a-f]+:[ ]+0f 01 dd[ ]+clgi[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 df[ ]+invlpga[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 de[ ]+skinit[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 dc[ ]+stgi[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 da[ ]+vmload[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d9[ ]+vmmcall[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d8[ ]+vmrun[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 db[ ]+vmsave[ ]* +[0-9a-f]+ : +[ ]*[0-9a-f]+:[ ]+0f 01 df[ ]+invlpga[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 da[ ]+vmload[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d8[ ]+vmrun[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 db[ ]+vmsave[ ]* +[0-9a-f]+ : +[ ]*[0-9a-f]+:[ ]+0f 01 de[ ]+skinit[ ]* +[ ]*[0-9a-f]+:[ ]+67 0f 01 df[ ]+(addr32 )?invlpga[ ]*\(%eax\),[ ]*%ecx +[ ]*[0-9a-f]+:[ ]+67 0f 01 da[ ]+(addr32 )?vmload[ ]*\(%eax\) +[ ]*[0-9a-f]+:[ ]+67 0f 01 d8[ ]+(addr32 )?vmrun[ ]*\(%eax\) +[ ]*[0-9a-f]+:[ ]+67 0f 01 db[ ]+(addr32 )?vmsave[ ]*\(%eax\) +[0-9a-f]+ : +[ ]*[0-9a-f]+:[ ]+0f 01 df[ ]+invlpga[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 da[ ]+vmload[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 d8[ ]+vmrun[ ]* +[ ]*[0-9a-f]+:[ ]+0f 01 db[ ]+vmsave[ ]* +[0-9a-f]+ : +[ ]*[0-9a-f]+:[ ]+0f 01 de[ ]+skinit[ ]* +[ ]*[0-9a-f]+:[ ]+67 0f 01 df[ ]+(addr32 )?invlpga[ ]*\(%eax\),[ ]*%ecx +[ ]*[0-9a-f]+:[ ]+67 0f 01 da[ ]+(addr32 )?vmload[ ]*\(%eax\) +[ ]*[0-9a-f]+:[ ]+67 0f 01 d8[ ]+(addr32 )?vmrun[ ]*\(%eax\) +[ ]*[0-9a-f]+:[ ]+67 0f 01 db[ ]+(addr32 )?vmsave[ ]*\(%eax\) +#pass --- /home/jbeulich/src/binutils/mainline/2005-06-16/include/opcode/i386.h 2005-05-13 12:17:11.000000000 +0200 +++ 2005-06-16/include/opcode/i386.h 2005-06-16 15:10:30.429213016 +0200 @@ -1379,6 +1379,22 @@ static const template i386_optab[] = {"swapgs", 0, 0x0f01, 0xf8, Cpu64, NoSuf|ImmExt, { 0, 0, 0} }, {"rdtscp", 0, 0x0f01, 0xf9, CpuSledgehammer,NoSuf|ImmExt, { 0, 0, 0} }, +/* AMD Pacifica additions. */ +{"clgi", 0, 0x0f01, 0xdd, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"invlpga", 0, 0x0f01, 0xdf, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +/* Need to ensure only "invlpga ...,%ecx" is accepted. */ +{"invlpga", 2, 0x0f01, 0xdf, CpuSVME, NoSuf|ImmExt, { AnyMem, Reg32, 0 } }, +{"skinit", 0, 0x0f01, 0xde, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"skinit", 1, 0x0f01, 0xde, CpuSVME, NoSuf|ImmExt, { AnyMem, 0, 0 } }, +{"stgi", 0, 0x0f01, 0xdc, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"vmload", 0, 0x0f01, 0xda, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"vmload", 1, 0x0f01, 0xda, CpuSVME, NoSuf|ImmExt, { AnyMem, 0, 0 } }, +{"vmmcall", 0, 0x0f01, 0xd9, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"vmrun", 0, 0x0f01, 0xd8, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"vmrun", 1, 0x0f01, 0xd8, CpuSVME, NoSuf|ImmExt, { AnyMem, 0, 0 } }, +{"vmsave", 0, 0x0f01, 0xdb, CpuSVME, NoSuf|ImmExt, { 0, 0, 0 } }, +{"vmsave", 1, 0x0f01, 0xdb, CpuSVME, NoSuf|ImmExt, { AnyMem, 0, 0 } }, + /* VIA PadLock extensions. */ {"xstore-rng",0, 0x000fa7, 0xc0, Cpu686|CpuPadLock, NoSuf|IsString|ImmExt, { 0, 0, 0} }, {"xcrypt-ecb",0, 0xf30fa7, 0xc8, Cpu686|CpuPadLock, NoSuf|IsString|ImmExt, { 0, 0, 0} }, --- /home/jbeulich/src/binutils/mainline/2005-06-16/opcodes/i386-dis.c 2005-05-25 08:49:01.000000000 +0200 +++ 2005-06-16/opcodes/i386-dis.c 2005-06-16 15:07:00.021199896 +0200 @@ -95,6 +95,7 @@ static void OP_3DNowSuffix (int, int); static void OP_SIMD_Suffix (int, int); static void SIMD_Fixup (int, int); static void PNI_Fixup (int, int); +static void SVME_Fixup (int, int); static void INVLPG_Fixup (int, int); static void BadOp (void); static void SEG_Fixup (int, int); @@ -1374,7 +1375,7 @@ static const struct dis386 grps[][8] = { { "sgdtIQ", M, XX, XX }, { "sidtIQ", PNI_Fixup, 0, XX, XX }, { "lgdt{Q|Q||}", M, XX, XX }, - { "lidt{Q|Q||}", M, XX, XX }, + { "lidt{Q|Q||}", SVME_Fixup, 0, XX, XX }, { "smswQ", Ev, XX, XX }, { "(bad)", XX, XX, XX }, { "lmsw", Ew, XX, XX }, @@ -4445,7 +4446,77 @@ PNI_Fixup (int extrachar ATTRIBUTE_UNUSE codep++; } else - OP_E (0, sizeflag); + OP_M (0, sizeflag); +} + +static void +SVME_Fixup (int bytemode, int sizeflag) +{ + const char *alt; + char *p; + + switch (*codep) + { + case 0xd8: + alt = "vmrun"; + break; + case 0xd9: + alt = "vmmcall"; + break; + case 0xda: + alt = "vmload"; + break; + case 0xdb: + alt = "vmsave"; + break; + case 0xdc: + alt = "stgi"; + break; + case 0xdd: + alt = "clgi"; + break; + case 0xde: + alt = "skinit"; + break; + case 0xdf: + alt = "invlpga"; + break; + default: + OP_M (bytemode, sizeflag); + return; + } + /* Override "lidt". */ + p = obuf + strlen (obuf) - 4; + /* We might have a suffix. */ + if (*p == 'i') + --p; + strcpy (p, alt); + if (!(prefixes & PREFIX_ADDR)) + { + ++codep; + return; + } + used_prefixes |= PREFIX_ADDR; + switch (*codep++) + { + case 0xdf: + strcpy (op2out, names32[1]); + two_source_ops = 1; + /* Fall through. */ + case 0xd8: + case 0xda: + case 0xdb: + *obufp++ = open_char; + if (mode_64bit || (sizeflag & AFLAG)) + alt = names32[0]; + else + alt = names16[0]; + strcpy (obufp, alt); + obufp += strlen (alt); + *obufp++ = close_char; + *obufp = '\0'; + break; + } } static void @@ -4462,7 +4533,7 @@ INVLPG_Fixup (int bytemode, int sizeflag alt = "rdtscp"; break; default: - OP_E (bytemode, sizeflag); + OP_M (bytemode, sizeflag); return; } /* Override "invlpg". */