/*
* Utility functions for x86 operand and address decoding
*
* Copyright (C) Intel Corporation 2017
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ratelimit.h>
#include <linux/mmu_context.h>
#include <asm/desc_defs.h>
#include <asm/desc.h>
#include <asm/inat.h>
#include <asm/insn.h>
#include <asm/insn-eval.h>
#include <asm/ldt.h>
#include <asm/vm86.h>
#undef pr_fmt
#define pr_fmt(fmt) "insn: " fmt
enum reg_type {
REG_TYPE_RM = 0,
REG_TYPE_INDEX,
REG_TYPE_BASE,
};
/**
* is_string_insn() - Determine if instruction is a string instruction
* @insn: Instruction containing the opcode to inspect
*
* Returns:
*
* true if the instruction, determined by the opcode, is any of the
* string instructions as defined in the Intel Software Development manual.
* False otherwise.
*/
static bool is_string_insn(struct insn *insn)
{
insn_get_opcode(insn);
/* All string instructions have a 1-byte opcode. */
if (insn->opcode.nbytes != 1)
return false;
switch (insn->opcode.bytes[0]) {
case 0x6c ... 0x6f: /* INS, OUTS */
case 0xa4 ... 0xa7: /* MOVS, CMPS */
case 0xaa ... 0xaf: /* STOS, LODS, SCAS */
return true;
default:
return false;
}
}
/**
* get_seg_reg_override_idx() - obtain segment register override index
* @insn: Valid instruction with segment override prefixes
*
* Inspect the instruction prefixes in @insn and find segment overrides, if any.
*
* Returns:
*
* A constant identifying the segment register to use, among CS, SS, DS,
* ES, FS, or GS. INAT_SEG_REG_DEFAULT is returned if no segment override
* prefixes were found.
*
* -EINVAL in case of error.
*/
static int get_seg_reg_override_idx(struct insn *insn)
{
int idx = INAT_SEG_REG_DEFAULT;
int num_overrides = 0, i;
insn_get_prefixes(insn);
/* Look for any segment override prefixes. */
for (i = 0; i < insn->prefixes.nbytes; i++) {
insn_attr_t attr;
attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
switch (attr) {
case INAT_MAKE_PREFIX(INAT_PFX_CS):
idx = INAT_SEG_REG_CS;
num_overrides++;
break;
case INAT_MAKE_PREFIX(INAT_PFX_SS):
idx = INAT_SEG_REG_SS;
num_overrides++;
break;
case INAT_MAKE_PREFIX(INAT_PFX_DS):
idx = INAT_SEG_REG_DS;
num_overrides++;
break;
case INAT_MAKE_PREFIX(INAT_PFX_ES):
idx = INAT_SEG_REG_ES<