x86_emulate.c
来自「linux 内核源代码」· C语言 代码 · 共 1,663 行 · 第 1/3 页
C
1,663 行
/****************************************************************************** * x86_emulate.c * * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. * * Copyright (c) 2005 Keir Fraser * * Linux coding style, mod r/m decoder, segment base fixes, real-mode * privileged instructions: * * Copyright (C) 2006 Qumranet * * Avi Kivity <avi@qumranet.com> * Yaniv Kamay <yaniv@qumranet.com> * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. * * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 */#ifndef __KERNEL__#include <stdio.h>#include <stdint.h>#include <public/xen.h>#define DPRINTF(_f, _a ...) printf( _f , ## _a )#else#include "kvm.h"#define DPRINTF(x...) do {} while (0)#endif#include "x86_emulate.h"#include <linux/module.h>/* * Opcode effective-address decode tables. * Note that we only emulate instructions that have at least one memory * operand (excluding implicit stack references). We assume that stack * references and instruction fetches will never occur in special memory * areas that require emulation. So, for example, 'mov <imm>,<reg>' need * not be handled. *//* Operand sizes: 8-bit operands or specified/overridden size. */#define ByteOp (1<<0) /* 8-bit operands. *//* Destination operand type. */#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */#define DstReg (2<<1) /* Register operand. */#define DstMem (3<<1) /* Memory operand. */#define DstMask (3<<1)/* Source operand type. */#define SrcNone (0<<3) /* No source operand. */#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */#define SrcReg (1<<3) /* Register operand. */#define SrcMem (2<<3) /* Memory operand. */#define SrcMem16 (3<<3) /* Memory operand (16-bit). */#define SrcMem32 (4<<3) /* Memory operand (32-bit). */#define SrcImm (5<<3) /* Immediate operand. */#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */#define SrcMask (7<<3)/* Generic ModRM decode. */#define ModRM (1<<6)/* Destination is only written; never read. */#define Mov (1<<7)#define BitOp (1<<8)static u8 opcode_table[256] = { /* 0x00 - 0x07 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x08 - 0x0F */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x10 - 0x17 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x18 - 0x1F */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x20 - 0x27 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, SrcImmByte, SrcImm, 0, 0, /* 0x28 - 0x2F */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x30 - 0x37 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x38 - 0x3F */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, 0, 0, 0, 0, /* 0x40 - 0x4F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x57 */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x58 - 0x5F */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x60 - 0x67 */ 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , 0, 0, 0, 0, /* 0x68 - 0x6F */ 0, 0, ImplicitOps|Mov, 0, SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ /* 0x70 - 0x77 */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x78 - 0x7F */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x80 - 0x87 */ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, /* 0x88 - 0x8F */ ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov, /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0, /* 0xA0 - 0xA7 */ ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov, ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, ByteOp | ImplicitOps, ImplicitOps, /* 0xA8 - 0xAF */ 0, 0, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, ByteOp | ImplicitOps, ImplicitOps, /* 0xB0 - 0xBF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 - 0xC7 */ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, ImplicitOps, 0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov, /* 0xC8 - 0xCF */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xD7 */ ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, 0, 0, 0, 0, /* 0xD8 - 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xE7 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE8 - 0xEF */ ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0, /* 0xF0 - 0xF7 */ 0, 0, 0, 0, ImplicitOps, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, /* 0xF8 - 0xFF */ 0, 0, 0, 0, 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM};static u16 twobyte_table[256] = { /* 0x00 - 0x0F */ 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0, ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, /* 0x10 - 0x1F */ 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2F */ ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3F */ ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x47 */ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, /* 0x48 - 0x4F */ DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, /* 0x50 - 0x5F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8F */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, /* 0xA8 - 0xAF */ 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, /* 0xB0 - 0xB7 */ ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem16 | ModRM | Mov, /* 0xB8 - 0xBF */ 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp, 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem16 | ModRM | Mov, /* 0xC0 - 0xCF */ 0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 - 0xFF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/* Type, address-of, and value of an instruction's operand. */struct operand { enum { OP_REG, OP_MEM, OP_IMM } type; unsigned int bytes; unsigned long val, orig_val, *ptr;};/* EFLAGS bit definitions. */#define EFLG_OF (1<<11)#define EFLG_DF (1<<10)#define EFLG_SF (1<<7)#define EFLG_ZF (1<<6)#define EFLG_AF (1<<4)#define EFLG_PF (1<<2)#define EFLG_CF (1<<0)/* * Instruction emulation: * Most instructions are emulated directly via a fragment of inline assembly * code. This allows us to save/restore EFLAGS and thus very easily pick up * any modified flags. */#if defined(CONFIG_X86_64)#define _LO32 "k" /* force 32-bit operand */#define _STK "%%rsp" /* stack pointer */#elif defined(__i386__)#define _LO32 "" /* force 32-bit operand */#define _STK "%%esp" /* stack pointer */#endif/* * These EFLAGS bits are restored from saved value during emulation, and * any changes are written back to the saved value after emulation. */#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)/* Before executing instruction: restore necessary bits in EFLAGS. */#define _PRE_EFLAGS(_sav, _msk, _tmp) \ /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */ \ "push %"_sav"; " \ "movl %"_msk",%"_LO32 _tmp"; " \ "andl %"_LO32 _tmp",("_STK"); " \ "pushf; " \ "notl %"_LO32 _tmp"; " \ "andl %"_LO32 _tmp",("_STK"); " \ "pop %"_tmp"; " \ "orl %"_LO32 _tmp",("_STK"); " \ "popf; " \ /* _sav &= ~msk; */ \ "movl %"_msk",%"_LO32 _tmp"; " \ "notl %"_LO32 _tmp"; " \ "andl %"_LO32 _tmp",%"_sav"; "/* After executing instruction: write-back necessary bits in EFLAGS. */#define _POST_EFLAGS(_sav, _msk, _tmp) \ /* _sav |= EFLAGS & _msk; */ \ "pushf; " \ "pop %"_tmp"; " \ "andl %"_msk",%"_LO32 _tmp"; " \ "orl %"_LO32 _tmp",%"_sav"; "/* Raw emulation: instruction has two explicit operands. */#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \ do { \ unsigned long _tmp; \ \ switch ((_dst).bytes) { \ case 2: \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","4","2") \ _op"w %"_wx"3,%1; " \ _POST_EFLAGS("0","4","2") \ : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : _wy ((_src).val), "i" (EFLAGS_MASK) ); \ break; \ case 4: \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","4","2") \ _op"l %"_lx"3,%1; " \ _POST_EFLAGS("0","4","2") \ : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : _ly ((_src).val), "i" (EFLAGS_MASK) ); \ break; \ case 8: \ __emulate_2op_8byte(_op, _src, _dst, \ _eflags, _qx, _qy); \ break; \ } \ } while (0)#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \ do { \ unsigned long _tmp; \ switch ( (_dst).bytes ) \ { \ case 1: \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","4","2") \ _op"b %"_bx"3,%1; " \ _POST_EFLAGS("0","4","2") \ : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : _by ((_src).val), "i" (EFLAGS_MASK) ); \ break; \ default: \ __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ _wx, _wy, _lx, _ly, _qx, _qy); \ break; \ } \ } while (0)/* Source operand is byte-sized and may be restricted to just %cl. */#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \ __emulate_2op(_op, _src, _dst, _eflags, \ "b", "c", "b", "c", "b", "c", "b", "c")/* Source operand is byte, word, long or quad sized. */#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \ __emulate_2op(_op, _src, _dst, _eflags, \ "b", "q", "w", "r", _LO32, "r", "", "r")/* Source operand is word, long or quad sized. */#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \ __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ "w", "r", _LO32, "r", "", "r")/* Instruction has only one explicit operand (no source operand). */#define emulate_1op(_op, _dst, _eflags) \ do { \ unsigned long _tmp; \ \ switch ( (_dst).bytes ) \ { \ case 1: \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","3","2") \ _op"b %1; " \ _POST_EFLAGS("0","3","2") \ : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : "i" (EFLAGS_MASK) ); \ break; \ case 2: \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","3","2") \ _op"w %1; " \ _POST_EFLAGS("0","3","2") \ : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : "i" (EFLAGS_MASK) ); \ break; \ case 4: \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","3","2") \ _op"l %1; " \ _POST_EFLAGS("0","3","2") \ : "=m" (_eflags), "=m" ((_dst).val), \ "=&r" (_tmp) \ : "i" (EFLAGS_MASK) ); \ break; \ case 8: \ __emulate_1op_8byte(_op, _dst, _eflags); \ break; \ } \ } while (0)/* Emulate an instruction with quadword operands (x86/64 only). */#if defined(CONFIG_X86_64)#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \ do { \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","4","2") \ _op"q %"_qx"3,%1; " \ _POST_EFLAGS("0","4","2") \ : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ : _qy ((_src).val), "i" (EFLAGS_MASK) ); \ } while (0)#define __emulate_1op_8byte(_op, _dst, _eflags) \ do { \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0","3","2") \ _op"q %1; " \ _POST_EFLAGS("0","3","2") \ : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ : "i" (EFLAGS_MASK) ); \ } while (0)#elif defined(__i386__)#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)#define __emulate_1op_8byte(_op, _dst, _eflags)#endif /* __i386__ *//* Fetch next part of the instruction being emulated. */#define insn_fetch(_type, _size, _eip) \({ unsigned long _x; \ rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \ (_size), ctxt->vcpu); \ if ( rc != 0 ) \ goto done; \ (_eip) += (_size); \ (_type)_x; \})/* Access/update address held in a register, based on addressing mode. */#define address_mask(reg) \ ((ad_bytes == sizeof(unsigned long)) ? \ (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1)))#define register_address(base, reg) \ ((base) + address_mask(reg))#define register_address_increment(reg, inc) \ do { \ /* signed type ensures sign extension to long */ \ int _inc = (inc); \ if ( ad_bytes == sizeof(unsigned long) ) \ (reg) += _inc; \ else \ (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) | \ (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \ } while (0)#define JMP_REL(rel) \ do { \ register_address_increment(_eip, rel); \ } while (0)/* * Given the 'reg' portion of a ModRM byte, and a register block, return a * pointer into the block that addresses the relevant register. * @highbyte_regs specifies whether to decode AH,CH,DH,BH. */static void *decode_register(u8 modrm_reg, unsigned long *regs, int highbyte_regs){ void *p; p = ®s[modrm_reg]; if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8) p = (unsigned char *)®s[modrm_reg & 3] + 1; return p;}static int read_descriptor(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, void *ptr, u16 *size, unsigned long *address, int op_bytes){ int rc; if (op_bytes == 2) op_bytes = 3; *address = 0; rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt->vcpu); if (rc) return rc; rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt->vcpu); return rc;}static int test_cc(unsigned int condition, unsigned int flags){ int rc = 0; switch ((condition & 15) >> 1) { case 0: /* o */ rc |= (flags & EFLG_OF); break; case 1: /* b/c/nae */ rc |= (flags & EFLG_CF); break; case 2: /* z/e */ rc |= (flags & EFLG_ZF); break; case 3: /* be/na */ rc |= (flags & (EFLG_CF|EFLG_ZF)); break; case 4: /* s */ rc |= (flags & EFLG_SF); break; case 5: /* p/pe */ rc |= (flags & EFLG_PF); break; case 7: /* le/ng */ rc |= (flags & EFLG_ZF); /* fall through */ case 6: /* l/nge */ rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF)); break; } /* Odd condition identifiers (lsb == 1) have inverted sense. */ return (!!rc ^ (condition & 1));}intx86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops){ unsigned d; u8 b, sib, twobyte = 0, rex_prefix = 0; u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; unsigned long *override_base = NULL; unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; int rc = 0; struct operand src, dst; unsigned long cr2 = ctxt->cr2; int mode = ctxt->mode; unsigned long modrm_ea; int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0; int no_wb = 0; u64 msr_data; /* Shadow copy of register state. Committed on successful emulation. */ unsigned long _regs[NR_VCPU_REGS]; unsigned long _eip = ctxt->vcpu->rip, _eflags = ctxt->eflags; unsigned long modrm_val = 0; memcpy(_regs, ctxt->vcpu->regs, sizeof _regs); switch (mode) { case X86EMUL_MODE_REAL: case X86EMUL_MODE_PROT16: op_bytes = ad_bytes = 2; break; case X86EMUL_MODE_PROT32: op_bytes = ad_bytes = 4; break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?