diff --git a/reactos/ntoskrnl/ex/amd64/fastinterlck.c b/reactos/ntoskrnl/ex/amd64/fastinterlck.c new file mode 100644 index 00000000000..b9ca32aab1b --- /dev/null +++ b/reactos/ntoskrnl/ex/amd64/fastinterlck.c @@ -0,0 +1,114 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: ntoskrnl/ex/fastinterlck.c + * PURPOSE: Portable Ex*Interlocked and REGISTER routines for amd64 + * PROGRAMMERS: ReactOS Portable Systems Group + * Timo Kreuzer + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +#undef ExInterlockedAddLargeInteger +#undef ExInterlockedAddUlong +#undef ExInterlockedExtendZone +#undef ExInterlockedInsertHeadList +#undef ExInterlockedInsertTailList +#undef ExInterlockedPopEntryList +#undef ExInterlockedPushEntryList +#undef ExInterlockedRemoveHeadList +#undef ExpInterlockedFlushSList +#undef ExpInterlockedPopEntrySList +#undef ExpInterlockedPushEntrySList + +/* FUNCTIONS ******************************************************************/ + +LARGE_INTEGER +ExInterlockedAddLargeInteger(IN PLARGE_INTEGER Addend, + IN LARGE_INTEGER Increment, + IN PKSPIN_LOCK Lock) +{ + LARGE_INTEGER Int; + Int.QuadPart = _InterlockedExchangeAdd64(&Addend->QuadPart, + Increment.QuadPart); + return Int; +} + +ULONG +ExInterlockedAddUlong(IN PULONG Addend, + IN ULONG Increment, + PKSPIN_LOCK Lock) +{ + return (ULONG)_InterlockedExchangeAdd((PLONG)Addend, Increment); +} + +PLIST_ENTRY +ExInterlockedInsertHeadList(IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY ListEntry, + IN PKSPIN_LOCK Lock) +{ + KIRQL OldIrql; + PLIST_ENTRY OldHead = NULL; + KeAcquireSpinLock(Lock, &OldIrql); + if (!IsListEmpty(ListHead)) OldHead = ListEntry->Flink; + InsertHeadList(ListHead, ListEntry); + KeReleaseSpinLock(Lock, OldIrql); + return OldHead; +} + +PLIST_ENTRY +ExInterlockedInsertTailList(IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY ListEntry, + IN PKSPIN_LOCK Lock) +{ + KIRQL OldIrql; + PLIST_ENTRY OldHead = NULL; + KeAcquireSpinLock(Lock, &OldIrql); + if (!IsListEmpty(ListHead)) OldHead = ListEntry->Blink; + InsertTailList(ListHead, ListEntry); + KeReleaseSpinLock(Lock, OldIrql); + return OldHead; +} + +PSINGLE_LIST_ENTRY +ExInterlockedPopEntryList(IN PSINGLE_LIST_ENTRY ListHead, + IN PKSPIN_LOCK Lock) +{ + KIRQL OldIrql; + PSINGLE_LIST_ENTRY FirstEntry; + KeAcquireSpinLock(Lock, &OldIrql); + FirstEntry = PopEntryList(ListHead); + KeReleaseSpinLock(Lock, OldIrql); + return FirstEntry; +} + +PSINGLE_LIST_ENTRY +ExInterlockedPushEntryList(IN PSINGLE_LIST_ENTRY ListHead, + IN PSINGLE_LIST_ENTRY ListEntry, + IN PKSPIN_LOCK Lock) +{ + KIRQL OldIrql; + PSINGLE_LIST_ENTRY OldHead = NULL; + KeAcquireSpinLock(Lock, &OldIrql); + OldHead = ListHead->Next; + PushEntryList(ListHead, ListEntry); + KeReleaseSpinLock(Lock, OldIrql); + return OldHead; +} + +PLIST_ENTRY +ExInterlockedRemoveHeadList(IN PLIST_ENTRY ListHead, + IN PKSPIN_LOCK Lock) +{ + KIRQL OldIrql; + PLIST_ENTRY OldHead = NULL; + KeAcquireSpinLock(Lock, &OldIrql); + if (!IsListEmpty(ListHead)) OldHead = RemoveHeadList(ListHead); + KeReleaseSpinLock(Lock, OldIrql); + return OldHead; +} + diff --git a/reactos/ntoskrnl/kd/amd64/kd.c b/reactos/ntoskrnl/kd/amd64/kd.c new file mode 100644 index 00000000000..74694d21ee3 --- /dev/null +++ b/reactos/ntoskrnl/kd/amd64/kd.c @@ -0,0 +1,23 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ke/i386/cpu.c + * PURPOSE: Routines for CPU-level support + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable, + ULONG BootPhase) +{ + UNIMPLEMENTED; +} diff --git a/reactos/ntoskrnl/kd/amd64/kdmemsup.c b/reactos/ntoskrnl/kd/amd64/kdmemsup.c new file mode 100644 index 00000000000..75f19a1cbce --- /dev/null +++ b/reactos/ntoskrnl/kd/amd64/kdmemsup.c @@ -0,0 +1,217 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel + * FILE: ntoskrnl/kd/amd64/kdmemsup.c + * PURPOSE: Kernel Debugger Safe Memory Support + * + * PROGRAMMERS: arty + */ + +#include +#define NDEBUG +#include + +#define HIGH_PHYS_MASK 0x80000000 +#define PAGE_TABLE_MASK 0x3ff +#define BIG_PAGE_SIZE (1<<22) +#define CR4_PAGE_SIZE_BIT 0x10 +#define PDE_PRESENT_BIT 0x01 +#define PDE_W_BIT 0x02 +#define PDE_PWT_BIT 0x08 +#define PDE_PCD_BIT 0x10 +#define PDE_ACCESSED_BIT 0x20 +#define PDE_DIRTY_BIT 0x40 +#define PDE_PS_BIT 0x80 + +#define MI_KDBG_TMP_PAGE_1 (HYPER_SPACE + 0x400000 - PAGE_SIZE) +#define MI_KDBG_TMP_PAGE_0 (MI_KDBG_TMP_PAGE_1 - PAGE_SIZE) + +/* VARIABLES ***************************************************************/ + +static BOOLEAN KdpPhysAccess = FALSE; + +static +ULONG_PTR +KdpPhysMap(ULONG_PTR PhysAddr, LONG Len) +{ + MMPTE TempPte; + PMMPTE PointerPte; + ULONG_PTR VirtAddr; + + TempPte.u.Long = PDE_PRESENT_BIT | PDE_W_BIT | PDE_PWT_BIT | + PDE_PCD_BIT | PDE_ACCESSED_BIT | PDE_DIRTY_BIT; + + if ((PhysAddr & (PAGE_SIZE - 1)) + Len > PAGE_SIZE) + { + TempPte.u.Hard.PageFrameNumber = (PhysAddr >> PAGE_SHIFT) + 1; + PointerPte = MiAddressToPte((PVOID)MI_KDBG_TMP_PAGE_1); + *PointerPte = TempPte; + VirtAddr = (ULONG_PTR)PointerPte << 10; + KeInvalidateTlbEntry((PVOID)VirtAddr); + } + + TempPte.u.Hard.PageFrameNumber = PhysAddr >> PAGE_SHIFT; + PointerPte = MiAddressToPte((PVOID)MI_KDBG_TMP_PAGE_0); + *PointerPte = TempPte; + VirtAddr = (ULONG_PTR)PointerPte << 10; + KeInvalidateTlbEntry((PVOID)VirtAddr); + + return VirtAddr + (PhysAddr & (PAGE_SIZE - 1)); +} + +static +ULONGLONG +KdpPhysRead(ULONG_PTR PhysAddr, LONG Len) +{ + ULONG_PTR Addr; + ULONGLONG Result = 0; + + Addr = KdpPhysMap(PhysAddr, Len); + + switch (Len) + { + case 8: + Result = *((PULONGLONG)Addr); + break; + case 4: + Result = *((PULONG)Addr); + break; + case 2: + Result = *((PUSHORT)Addr); + break; + case 1: + Result = *((PUCHAR)Addr); + break; + } + + return Result; +} + +static +VOID +KdpPhysWrite(ULONG_PTR PhysAddr, LONG Len, ULONGLONG Value) +{ + ULONG_PTR Addr; + + Addr = KdpPhysMap(PhysAddr, Len); + + switch (Len) + { + case 8: + *((PULONGLONG)Addr) = Value; + break; + case 4: + *((PULONG)Addr) = Value; + break; + case 2: + *((PUSHORT)Addr) = Value; + break; + case 1: + *((PUCHAR)Addr) = Value; + break; + } +} + +BOOLEAN +NTAPI +KdpTranslateAddress(ULONG_PTR Addr, PULONG_PTR ResultAddr) +{ + ULONG_PTR CR3Value = __readcr3(); + ULONG_PTR CR4Value = __readcr4(); + ULONG_PTR PageDirectory = (CR3Value & ~(PAGE_SIZE-1)) + + ((Addr >> 22) * sizeof(ULONG)); + ULONG_PTR PageDirectoryEntry = KdpPhysRead(PageDirectory, sizeof(ULONG)); + + /* Not present -> fail */ + if (!(PageDirectoryEntry & PDE_PRESENT_BIT)) + { + return FALSE; + } + + /* Big Page? */ + if ((PageDirectoryEntry & PDE_PS_BIT) && (CR4Value & CR4_PAGE_SIZE_BIT)) + { + *ResultAddr = (PageDirectoryEntry & ~(BIG_PAGE_SIZE-1)) + + (Addr & (BIG_PAGE_SIZE-1)); + return TRUE; + } + else + { + ULONG_PTR PageTableAddr = + (PageDirectoryEntry & ~(PAGE_SIZE-1)) + + ((Addr >> PAGE_SHIFT) & PAGE_TABLE_MASK) * sizeof(ULONG); + ULONG_PTR PageTableEntry = KdpPhysRead(PageTableAddr, sizeof(ULONG)); + if (PageTableEntry & PDE_PRESENT_BIT) + { + *ResultAddr = (PageTableEntry & ~(PAGE_SIZE-1)) + + (Addr & (PAGE_SIZE-1)); + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN +NTAPI +KdpSafeReadMemory(ULONG_PTR Addr, LONG Len, PVOID Value) +{ + ULONG_PTR ResultPhysAddr; + + if (!KdpPhysAccess) + { + memcpy(Value, (PVOID)Addr, Len); + return TRUE; + } + + memset(Value, 0, Len); + + if (!KdpTranslateAddress(Addr, &ResultPhysAddr)) + return FALSE; + + switch (Len) + { + case 8: + *((PULONGLONG)Value) = KdpPhysRead(ResultPhysAddr, Len); + break; + case 4: + *((PULONG)Value) = KdpPhysRead(ResultPhysAddr, Len); + break; + case 2: + *((PUSHORT)Value) = KdpPhysRead(ResultPhysAddr, Len); + break; + case 1: + *((PUCHAR)Value) = KdpPhysRead(ResultPhysAddr, Len); + break; + } + + return TRUE; +} + +BOOLEAN +NTAPI +KdpSafeWriteMemory(ULONG_PTR Addr, LONG Len, ULONGLONG Value) +{ + ULONG_PTR ResultPhysAddr; + + if (!KdpPhysAccess) + { + memcpy((PVOID)Addr, &Value, Len); + return TRUE; + } + + if (!KdpTranslateAddress(Addr, &ResultPhysAddr)) + return FALSE; + + KdpPhysWrite(ResultPhysAddr, Len, Value); + return TRUE; +} + +VOID +NTAPI +KdpEnableSafeMem(VOID) +{ + KdpPhysAccess = TRUE; +} + +/* EOF */ diff --git a/reactos/ntoskrnl/kdbg/amd64/dis-asm.h b/reactos/ntoskrnl/kdbg/amd64/dis-asm.h new file mode 100644 index 00000000000..4052910d451 --- /dev/null +++ b/reactos/ntoskrnl/kdbg/amd64/dis-asm.h @@ -0,0 +1,330 @@ +/* Interface between the opcode library and its callers. + + Copyright 2001, 2002 Free Software Foundation, Inc. + + 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. + + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +/* #include */ +/* #include "bfd.h" */ +#endif + +typedef int (*fprintf_ftype) PARAMS((PTR, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + PTR stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; +#if 0 + enum bfd_endian endian; +#endif + /* An arch/mach-specific bitmask of selected instruction subsets, mainly + for processors with run-time-switchable instruction sets. The default, + zero, means that there is no constraint. CGEN-based opcodes ports + may use ISA_foo masks. */ + unsigned long insn_sets; + +#if 0 + /* Some targets need information about the current section to accurately + display insns. If this is NULL, the target disassembler function + will have to make its best guess. */ + asection *section; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; +#endif + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info * info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + unsigned int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Number of octets per incremented target address + Normally one, but some DSPs have byte sizes of 16 or 32 bits. */ + unsigned int octets_per_byte; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of octets processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_i386_att PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_intel PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ia64 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i370 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc12 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_avr PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d30v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_dlx PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_fr30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i860 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ip2k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mcore PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mmix PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_msp430 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_openrisc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_or32 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_or32 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pdp11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic4x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic54x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_vax PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_xstormy16 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh64 PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_sh64x_media PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_frv PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_iq2000 PARAMS ((bfd_vma, disassemble_info *)); + +extern disassembler_ftype arc_get_disassembler PARAMS ((void *)); +extern disassembler_ftype cris_get_disassembler PARAMS ((bfd *)); + +extern void print_mips_disassembler_options PARAMS ((FILE *)); +extern void print_ppc_disassembler_options PARAMS ((FILE *)); +extern void print_arm_disassembler_options PARAMS ((FILE *)); +extern void parse_arm_disassembler_option PARAMS ((char *)); +extern int get_arm_regname_num_options PARAMS ((void)); +extern int set_arm_regname_option PARAMS ((int)); +extern int get_arm_regnames PARAMS ((int, const char **, const char **, const char ***)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + +/* Document any target specific options available from the disassembler. */ +extern void disassembler_usage PARAMS ((FILE *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Always true. */ +extern int generic_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).insn_sets = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).octets_per_byte = 1, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (fprintf_ftype)(FPRINTF_FUNC), \ + (INFO).stream = (PTR)(STREAM), \ + (INFO).section = NULL, \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).private_data = NULL, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).disassembler_options = NULL, \ + (INFO).insn_info_valid = 0 + +#ifdef __cplusplus +} +#endif + +#endif /* ! defined (DIS_ASM_H) */ diff --git a/reactos/ntoskrnl/kdbg/amd64/i386-dis.c b/reactos/ntoskrnl/kdbg/amd64/i386-dis.c new file mode 100644 index 00000000000..ac9d153d3dc --- /dev/null +++ b/reactos/ntoskrnl/kdbg/amd64/i386-dis.c @@ -0,0 +1,4300 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/kdbg/i386/i386-dis.c + * PURPOSE: No purpose listed. + * + * PROGRAMMERS: No programmer listed. + */ + +#include +#define NDEBUG +#include + +/* ReactOS compatibility stuff. */ +#define PARAMS(X) X +#define PTR void* +typedef enum bfd_flavour +{ + bfd_target_unknown_flavour, +} bfd_flavour; +typedef enum bfd_architecture +{ + bfd_arch_i386, +} bfd_arch; +typedef ULONG_PTR bfd_vma; +typedef unsigned char bfd_byte; +enum bfd_endian { BFD_ENDIAN_BIG, BIG_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; +typedef void* bfd; +typedef LONG_PTR bfd_signed_vma; +#define bfd_mach_x86_64_intel_syntax 0 +#define bfd_mach_x86_64 1 +#define bfd_mach_i386_i386_intel_syntax 2 +#define bfd_mach_i386_i386 3 +#define bfd_mach_i386_i8086 4 +#define abort() DbgBreakPoint(); +#define _(X) X +#define ATTRIBUTE_UNUSED +extern int sprintf(char *str, const char *format, ...); +#define sprintf_vma(BUF, VMA) sprintf(BUF, "%p", VMA) +#include +#define _INC_SETJMPEX +struct disassemble_info; + +int +print_insn_i386 (bfd_vma pc, struct disassemble_info *info); + +int +KdbpPrintDisasm(void* Ignored, const char* fmt, ...) +{ + va_list ap; + static char buffer[256]; + int ret; + + va_start(ap, fmt); + ret = vsprintf(buffer, fmt, ap); + DbgPrint("%s", buffer); + va_end(ap); + return(ret); +} + +int +KdbpNopPrintDisasm(void* Ignored, const char* fmt, ...) +{ + return(0); +} + +static int +KdbpReadMemory(ULONG_PTR Addr, unsigned char* Data, unsigned int Length, + struct disassemble_info * Ignored) +{ + return KdbpSafeReadMemory(Data, (void *)Addr, Length); /* 0 means no error */ +} + +static void +KdbpMemoryError(int Status, ULONG_PTR Addr, + struct disassemble_info * Ignored) +{ +} + +static void +KdbpPrintAddressInCode(ULONG_PTR Addr, struct disassemble_info * Ignored) +{ + if (!KdbSymPrintAddress((void*)Addr)) + { + DbgPrint("<%p>", Addr); + } +} + +static void +KdbpNopPrintAddress(ULONG_PTR Addr, struct disassemble_info * Ignored) +{ +} + +#include "dis-asm.h" + +LONG +KdbpGetInstLength(IN ULONG_PTR Address) +{ + disassemble_info info; + + info.fprintf_func = KdbpNopPrintDisasm; + info.stream = NULL; + info.application_data = NULL; + info.flavour = bfd_target_unknown_flavour; + info.arch = bfd_arch_i386; + info.mach = bfd_mach_x86_64; + info.insn_sets = 0; + info.flags = 0; + info.read_memory_func = KdbpReadMemory; + info.memory_error_func = KdbpMemoryError; + info.print_address_func = KdbpNopPrintAddress; + info.symbol_at_address_func = NULL; + info.buffer = NULL; + info.buffer_vma = info.buffer_length = 0; + info.bytes_per_chunk = 0; + info.display_endian = BIG_ENDIAN_LITTLE; + info.disassembler_options = NULL; + + return(print_insn_i386(Address, &info)); +} + +LONG +KdbpDisassemble(IN ULONG_PTR Address, IN ULONG IntelSyntax) +{ + disassemble_info info; + + info.fprintf_func = KdbpPrintDisasm; + info.stream = NULL; + info.application_data = NULL; + info.flavour = bfd_target_unknown_flavour; + info.arch = bfd_arch_i386; + info.mach = IntelSyntax ? bfd_mach_i386_i386_intel_syntax : bfd_mach_i386_i386; + info.insn_sets = 0; + info.flags = 0; + info.read_memory_func = KdbpReadMemory; + info.memory_error_func = KdbpMemoryError; + info.print_address_func = KdbpPrintAddressInCode; + info.symbol_at_address_func = NULL; + info.buffer = NULL; + info.buffer_vma = info.buffer_length = 0; + info.bytes_per_chunk = 0; + info.display_endian = BIG_ENDIAN_LITTLE; + info.disassembler_options = NULL; + + return(print_insn_i386(Address, &info)); +} + +/* Print i386 instructions for GDB, the GNU debugger. + Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2001 + Free Software Foundation, Inc. + +This file is part of GDB. + +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. +*/ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + * x86-64 support added by Jan Hubicka (jh@suse.cz) + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include "dis-asm.h" +#if 0 +#include "sysdep.h" +#include "opintl.h" +#endif + +#define MAXLEN 20 + +#include + +#ifndef UNIXWARE_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes. */ +#define UNIXWARE_COMPAT 1 +#endif + +static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); +static void ckprefix PARAMS ((void)); +static const char *prefix_name PARAMS ((int, int)); +static int print_insn PARAMS ((bfd_vma, disassemble_info *)); +static void dofloat PARAMS ((int)); +static void OP_ST PARAMS ((int, int)); +static void OP_STi PARAMS ((int, int)); +static int putop PARAMS ((const char *, int)); +static void oappend PARAMS ((const char *)); +static void append_seg PARAMS ((void)); +static void OP_indirE PARAMS ((int, int)); +static void print_operand_value PARAMS ((char *, int, bfd_vma)); +static void OP_E PARAMS ((int, int)); +static void OP_G PARAMS ((int, int)); +static bfd_vma get64 PARAMS ((void)); +static bfd_signed_vma get32 PARAMS ((void)); +static bfd_signed_vma get32s PARAMS ((void)); +static int get16 PARAMS ((void)); +static void set_op PARAMS ((bfd_vma, int)); +static void OP_REG PARAMS ((int, int)); +static void OP_IMREG PARAMS ((int, int)); +static void OP_I PARAMS ((int, int)); +static void OP_I64 PARAMS ((int, int)); +static void OP_sI PARAMS ((int, int)); +static void OP_J PARAMS ((int, int)); +static void OP_SEG PARAMS ((int, int)); +static void OP_DIR PARAMS ((int, int)); +static void OP_OFF PARAMS ((int, int)); +static void OP_OFF64 PARAMS ((int, int)); +static void ptr_reg PARAMS ((int, int)); +static void OP_ESreg PARAMS ((int, int)); +static void OP_DSreg PARAMS ((int, int)); +static void OP_C PARAMS ((int, int)); +static void OP_D PARAMS ((int, int)); +static void OP_T PARAMS ((int, int)); +static void OP_Rd PARAMS ((int, int)); +static void OP_MMX PARAMS ((int, int)); +static void OP_XMM PARAMS ((int, int)); +static void OP_EM PARAMS ((int, int)); +static void OP_EX PARAMS ((int, int)); +static void OP_MS PARAMS ((int, int)); +static void OP_XS PARAMS ((int, int)); +static void OP_3DNowSuffix PARAMS ((int, int)); +static void OP_SIMD_Suffix PARAMS ((int, int)); +static void SIMD_Fixup PARAMS ((int, int)); +static void BadOp PARAMS ((void)); + +struct dis_private { + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + int orig_sizeflag; + jmp_buf bailout; +}; + +/* The opcode for the fwait instruction, which we treat as a prefix + when we can. */ +#define FWAIT_OPCODE (0x9b) + +/* Set to 1 for 64bit mode disassembly. */ +static int mode_64bit = 1; + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* REX prefix the current instruction. See below. */ +static int rex; +/* Bits of REX we've already used. */ +static int rex_used; +#define REX_MODE64 8 +#define REX_EXTX 4 +#define REX_EXTY 2 +#define REX_EXTZ 1 +/* Mark parts used in the REX prefix. When we are testing for + empty prefix (for 8bit register REX extension), just mask it + out. Otherwise test for REX bit is excuse for existence of REX + only in case value is nonzero. */ +#define USED_REX(value) \ + { \ + if (value) \ + rex_used |= (rex & value) ? (value) | 0x40 : 0; \ + else \ + rex_used |= 0x40; \ + } + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct dis_private *priv = (struct dis_private *) info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +#define XX NULL, 0 + +#define Eb OP_E, b_mode +#define Ev OP_E, v_mode +#define Ed OP_E, d_mode +#define indirEb OP_indirE, b_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 /* lea, lgdt, etc. */ +#define Mp OP_E, 0 /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Gb OP_G, b_mode +#define Gv OP_G, v_mode +#define Gd OP_G, d_mode +#define Gw OP_G, w_mode +#define Rd OP_Rd, d_mode +#define Rm OP_Rd, m_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iq OP_I, q_mode +#define Iv64 OP_I64, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define Cm OP_C, m_mode +#define Dm OP_D, m_mode +#define Td OP_T, d_mode + +#define RMeAX OP_REG, eAX_reg +#define RMeBX OP_REG, eBX_reg +#define RMeCX OP_REG, eCX_reg +#define RMeDX OP_REG, eDX_reg +#define RMeSP OP_REG, eSP_reg +#define RMeBP OP_REG, eBP_reg +#define RMeSI OP_REG, eSI_reg +#define RMeDI OP_REG, eDI_reg +#define RMrAX OP_REG, rAX_reg +#define RMrBX OP_REG, rBX_reg +#define RMrCX OP_REG, rCX_reg +#define RMrDX OP_REG, rDX_reg +#define RMrSP OP_REG, rSP_reg +#define RMrBP OP_REG, rBP_reg +#define RMrSI OP_REG, rSI_reg +#define RMrDI OP_REG, rDI_reg +#define RMAL OP_REG, al_reg +#define RMAL OP_REG, al_reg +#define RMCL OP_REG, cl_reg +#define RMDL OP_REG, dl_reg +#define RMBL OP_REG, bl_reg +#define RMAH OP_REG, ah_reg +#define RMCH OP_REG, ch_reg +#define RMDH OP_REG, dh_reg +#define RMBH OP_REG, bh_reg +#define RMAX OP_REG, ax_reg +#define RMDX OP_REG, dx_reg + +#define eAX OP_IMREG, eAX_reg +#define eBX OP_IMREG, eBX_reg +#define eCX OP_IMREG, eCX_reg +#define eDX OP_IMREG, eDX_reg +#define eSP OP_IMREG, eSP_reg +#define eBP OP_IMREG, eBP_reg +#define eSI OP_IMREG, eSI_reg +#define eDI OP_IMREG, eDI_reg +#define AL OP_IMREG, al_reg +#define AL OP_IMREG, al_reg +#define CL OP_IMREG, cl_reg +#define DL OP_IMREG, dl_reg +#define BL OP_IMREG, bl_reg +#define AH OP_IMREG, ah_reg +#define CH OP_IMREG, ch_reg +#define DH OP_IMREG, dh_reg +#define BH OP_IMREG, bh_reg +#define AX OP_IMREG, ax_reg +#define DX OP_IMREG, dx_reg +#define indirDX OP_IMREG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, 0 +#define Ob OP_OFF, b_mode +#define Ob64 OP_OFF64, b_mode +#define Ov OP_OFF, v_mode +#define Ov64 OP_OFF64, v_mode +#define Xb OP_DSreg, eSI_reg +#define Xv OP_DSreg, eSI_reg +#define Yb OP_ESreg, eDI_reg +#define Yv OP_ESreg, eDI_reg +#define DSBX OP_DSreg, eBX_reg + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +#define MX OP_MMX, 0 +#define XM OP_XMM, 0 +#define EM OP_EM, v_mode +#define EX OP_EX, v_mode +#define MS OP_MS, v_mode +#define XS OP_XS, v_mode +#define None OP_E, 0 +#define OPSUF OP_3DNowSuffix, 0 +#define OPSIMD OP_SIMD_Suffix, 0 + +#define cond_jump_flag NULL, cond_jump_mode +#define loop_jcxz_flag NULL, loop_jcxz_mode + +/* bits in sizeflag */ +#define SUFFIX_ALWAYS 4 +#define AFLAG 2 +#define DFLAG 1 + +#define b_mode 1 /* byte operand */ +#define v_mode 2 /* operand size depends on prefixes */ +#define w_mode 3 /* word operand */ +#define d_mode 4 /* double word operand */ +#define q_mode 5 /* quad word operand */ +#define x_mode 6 +#define m_mode 7 /* d_mode in 32bit, q_mode in 64bit mode. */ +#define cond_jump_mode 8 +#define loop_jcxz_mode 9 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 + +#define eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define rAX_reg 132 +#define rCX_reg 133 +#define rDX_reg 134 +#define rBX_reg 135 +#define rSP_reg 136 +#define rBP_reg 137 +#define rSI_reg 138 +#define rDI_reg 139 + +#define indir_dx_reg 150 + +#define FLOATCODE 1 +#define USE_GROUPS 2 +#define USE_PREFIX_USER_TABLE 3 +#define X86_64_SPECIAL 4 + +#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 + +#define GRP1b NULL, NULL, USE_GROUPS, NULL, 0, NULL, 0 +#define GRP1S NULL, NULL, USE_GROUPS, NULL, 1, NULL, 0 +#define GRP1Ss NULL, NULL, USE_GROUPS, NULL, 2, NULL, 0 +#define GRP2b NULL, NULL, USE_GROUPS, NULL, 3, NULL, 0 +#define GRP2S NULL, NULL, USE_GROUPS, NULL, 4, NULL, 0 +#define GRP2b_one NULL, NULL, USE_GROUPS, NULL, 5, NULL, 0 +#define GRP2S_one NULL, NULL, USE_GROUPS, NULL, 6, NULL, 0 +#define GRP2b_cl NULL, NULL, USE_GROUPS, NULL, 7, NULL, 0 +#define GRP2S_cl NULL, NULL, USE_GROUPS, NULL, 8, NULL, 0 +#define GRP3b NULL, NULL, USE_GROUPS, NULL, 9, NULL, 0 +#define GRP3S NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0 +#define GRP4 NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0 +#define GRP5 NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0 +#define GRP6 NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0 +#define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0 +#define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0 +#define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0 +#define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0 +#define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0 +#define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0 +#define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0 +#define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0 +#define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0 + +#define PREGRP0 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 0, NULL, 0 +#define PREGRP1 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 1, NULL, 0 +#define PREGRP2 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 2, NULL, 0 +#define PREGRP3 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 3, NULL, 0 +#define PREGRP4 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 4, NULL, 0 +#define PREGRP5 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 5, NULL, 0 +#define PREGRP6 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 6, NULL, 0 +#define PREGRP7 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 7, NULL, 0 +#define PREGRP8 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 8, NULL, 0 +#define PREGRP9 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 9, NULL, 0 +#define PREGRP10 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0 +#define PREGRP11 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0 +#define PREGRP12 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0 +#define PREGRP13 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0 +#define PREGRP14 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0 +#define PREGRP15 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0 +#define PREGRP16 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0 +#define PREGRP17 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0 +#define PREGRP18 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0 +#define PREGRP19 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0 +#define PREGRP20 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0 +#define PREGRP21 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0 +#define PREGRP22 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0 +#define PREGRP23 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0 +#define PREGRP24 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0 +#define PREGRP25 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0 +#define PREGRP26 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0 + +#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0 + +typedef void (*op_rtn) PARAMS ((int bytemode, int sizeflag)); + +struct dis386 { + const char *name; + op_rtn op1; + int bytemode1; + op_rtn op2; + int bytemode2; + op_rtn op3; + int bytemode3; +}; + +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'F' => print 'w' or 'l' depending on address size prefix (loop insns) + 'H' => print ",pt" or ",pn" branch hint + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'O' => print 'd', or 'o' + 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, + . or suffix_always is true. print 'q' if rex prefix is present. + 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always + . is true + 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) + 'S' => print 'w', 'l' or 'q' if suffix_always is true + 'T' => print 'q' in 64bit mode and behave as 'P' otherwise + 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise + 'X' => print 's', 'd' depending on data16 prefix (for XMM) + 'W' => print 'b' or 'w' ("w" or "de" in intel mode) + 'Y' => 'q' if instruction has an REX 64bit overwrite prefix + + Many of the above letters print nothing in Intel mode. See "putop" + for the details. + + Braces '{' and '}', and vertical bars '|', indicate alternative + mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel + modes. In cases where there are only two alternatives, the X86_64 + instruction is reserved, and "(bad)" is printed. +*/ + +static const struct dis386 dis386[] = { + /* 00 */ + { "addB", Eb, Gb, XX }, + { "addS", Ev, Gv, XX }, + { "addB", Gb, Eb, XX }, + { "addS", Gv, Ev, XX }, + { "addB", AL, Ib, XX }, + { "addS", eAX, Iv, XX }, + { "push{T|}", es, XX, XX }, + { "pop{T|}", es, XX, XX }, + /* 08 */ + { "orB", Eb, Gb, XX }, + { "orS", Ev, Gv, XX }, + { "orB", Gb, Eb, XX }, + { "orS", Gv, Ev, XX }, + { "orB", AL, Ib, XX }, + { "orS", eAX, Iv, XX }, + { "push{T|}", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcB", Eb, Gb, XX }, + { "adcS", Ev, Gv, XX }, + { "adcB", Gb, Eb, XX }, + { "adcS", Gv, Ev, XX }, + { "adcB", AL, Ib, XX }, + { "adcS", eAX, Iv, XX }, + { "push{T|}", ss, XX, XX }, + { "popT|}", ss, XX, XX }, + /* 18 */ + { "sbbB", Eb, Gb, XX }, + { "sbbS", Ev, Gv, XX }, + { "sbbB", Gb, Eb, XX }, + { "sbbS", Gv, Ev, XX }, + { "sbbB", AL, Ib, XX }, + { "sbbS", eAX, Iv, XX }, + { "push{T|}", ds, XX, XX }, + { "pop{T|}", ds, XX, XX }, + /* 20 */ + { "andB", Eb, Gb, XX }, + { "andS", Ev, Gv, XX }, + { "andB", Gb, Eb, XX }, + { "andS", Gv, Ev, XX }, + { "andB", AL, Ib, XX }, + { "andS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa{|}", XX, XX, XX }, + /* 28 */ + { "subB", Eb, Gb, XX }, + { "subS", Ev, Gv, XX }, + { "subB", Gb, Eb, XX }, + { "subS", Gv, Ev, XX }, + { "subB", AL, Ib, XX }, + { "subS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das{|}", XX, XX, XX }, + /* 30 */ + { "xorB", Eb, Gb, XX }, + { "xorS", Ev, Gv, XX }, + { "xorB", Gb, Eb, XX }, + { "xorS", Gv, Ev, XX }, + { "xorB", AL, Ib, XX }, + { "xorS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa{|}", XX, XX, XX }, + /* 38 */ + { "cmpB", Eb, Gb, XX }, + { "cmpS", Ev, Gv, XX }, + { "cmpB", Gb, Eb, XX }, + { "cmpS", Gv, Ev, XX }, + { "cmpB", AL, Ib, XX }, + { "cmpS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas{|}", XX, XX, XX }, + /* 40 */ + { "inc{S|}", RMeAX, XX, XX }, + { "inc{S|}", RMeCX, XX, XX }, + { "inc{S|}", RMeDX, XX, XX }, + { "inc{S|}", RMeBX, XX, XX }, + { "inc{S|}", RMeSP, XX, XX }, + { "inc{S|}", RMeBP, XX, XX }, + { "inc{S|}", RMeSI, XX, XX }, + { "inc{S|}", RMeDI, XX, XX }, + /* 48 */ + { "dec{S|}", RMeAX, XX, XX }, + { "dec{S|}", RMeCX, XX, XX }, + { "dec{S|}", RMeDX, XX, XX }, + { "dec{S|}", RMeBX, XX, XX }, + { "dec{S|}", RMeSP, XX, XX }, + { "dec{S|}", RMeBP, XX, XX }, + { "dec{S|}", RMeSI, XX, XX }, + { "dec{S|}", RMeDI, XX, XX }, + /* 50 */ + { "pushS", RMrAX, XX, XX }, + { "pushS", RMrCX, XX, XX }, + { "pushS", RMrDX, XX, XX }, + { "pushS", RMrBX, XX, XX }, + { "pushS", RMrSP, XX, XX }, + { "pushS", RMrBP, XX, XX }, + { "pushS", RMrSI, XX, XX }, + { "pushS", RMrDI, XX, XX }, + /* 58 */ + { "popS", RMrAX, XX, XX }, + { "popS", RMrCX, XX, XX }, + { "popS", RMrDX, XX, XX }, + { "popS", RMrBX, XX, XX }, + { "popS", RMrSP, XX, XX }, + { "popS", RMrBP, XX, XX }, + { "popS", RMrSI, XX, XX }, + { "popS", RMrDI, XX, XX }, + /* 60 */ + { "pusha{P|}", XX, XX, XX }, + { "popa{P|}", XX, XX, XX }, + { "bound{S|}", Gv, Ma, XX }, + { X86_64_0 }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* adr size prefix */ + /* 68 */ + { "pushT", Iq, XX, XX }, + { "imulS", Gv, Ev, Iv }, + { "pushT", sIb, XX, XX }, + { "imulS", Gv, Ev, sIb }, + { "ins{b||b|}", Yb, indirDX, XX }, + { "ins{R||R|}", Yv, indirDX, XX }, + { "outs{b||b|}", indirDX, Xb, XX }, + { "outs{R||R|}", indirDX, Xv, XX }, + /* 70 */ + { "joH", Jb, XX, cond_jump_flag }, + { "jnoH", Jb, XX, cond_jump_flag }, + { "jbH", Jb, XX, cond_jump_flag }, + { "jaeH", Jb, XX, cond_jump_flag }, + { "jeH", Jb, XX, cond_jump_flag }, + { "jneH", Jb, XX, cond_jump_flag }, + { "jbeH", Jb, XX, cond_jump_flag }, + { "jaH", Jb, XX, cond_jump_flag }, + /* 78 */ + { "jsH", Jb, XX, cond_jump_flag }, + { "jnsH", Jb, XX, cond_jump_flag }, + { "jpH", Jb, XX, cond_jump_flag }, + { "jnpH", Jb, XX, cond_jump_flag }, + { "jlH", Jb, XX, cond_jump_flag }, + { "jgeH", Jb, XX, cond_jump_flag }, + { "jleH", Jb, XX, cond_jump_flag }, + { "jgH", Jb, XX, cond_jump_flag }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", XX, XX, XX }, + { GRP1Ss }, + { "testB", Eb, Gb, XX }, + { "testS", Ev, Gv, XX }, + { "xchgB", Eb, Gb, XX }, + { "xchgS", Ev, Gv, XX }, + /* 88 */ + { "movB", Eb, Gb, XX }, + { "movS", Ev, Gv, XX }, + { "movB", Gb, Eb, XX }, + { "movS", Gv, Ev, XX }, + { "movQ", Ev, Sw, XX }, + { "leaS", Gv, M, XX }, + { "movQ", Sw, Ev, XX }, + { "popU", Ev, XX, XX }, + /* 90 */ + { "nop", XX, XX, XX }, + /* FIXME: NOP with REPz prefix is called PAUSE. */ + { "xchgS", RMeCX, eAX, XX }, + { "xchgS", RMeDX, eAX, XX }, + { "xchgS", RMeBX, eAX, XX }, + { "xchgS", RMeSP, eAX, XX }, + { "xchgS", RMeBP, eAX, XX }, + { "xchgS", RMeSI, eAX, XX }, + { "xchgS", RMeDI, eAX, XX }, + /* 98 */ + { "cW{tR||tR|}", XX, XX, XX }, + { "cR{tO||tO|}", XX, XX, XX }, + { "lcall{T|}", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushfT", XX, XX, XX }, + { "popfT", XX, XX, XX }, + { "sahf{|}", XX, XX, XX }, + { "lahf{|}", XX, XX, XX }, + /* a0 */ + { "movB", AL, Ob64, XX }, + { "movS", eAX, Ov64, XX }, + { "movB", Ob64, AL, XX }, + { "movS", Ov64, eAX, XX }, + { "movs{b||b|}", Yb, Xb, XX }, + { "movs{R||R|}", Yv, Xv, XX }, + { "cmps{b||b|}", Xb, Yb, XX }, + { "cmps{R||R|}", Xv, Yv, XX }, + /* a8 */ + { "testB", AL, Ib, XX }, + { "testS", eAX, Iv, XX }, + { "stosB", Yb, AL, XX }, + { "stosS", Yv, eAX, XX }, + { "lodsB", AL, Xb, XX }, + { "lodsS", eAX, Xv, XX }, + { "scasB", AL, Yb, XX }, + { "scasS", eAX, Yv, XX }, + /* b0 */ + { "movB", RMAL, Ib, XX }, + { "movB", RMCL, Ib, XX }, + { "movB", RMDL, Ib, XX }, + { "movB", RMBL, Ib, XX }, + { "movB", RMAH, Ib, XX }, + { "movB", RMCH, Ib, XX }, + { "movB", RMDH, Ib, XX }, + { "movB", RMBH, Ib, XX }, + /* b8 */ + { "movS", RMeAX, Iv64, XX }, + { "movS", RMeCX, Iv64, XX }, + { "movS", RMeDX, Iv64, XX }, + { "movS", RMeBX, Iv64, XX }, + { "movS", RMeSP, Iv64, XX }, + { "movS", RMeBP, Iv64, XX }, + { "movS", RMeSI, Iv64, XX }, + { "movS", RMeDI, Iv64, XX }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "retT", Iw, XX, XX }, + { "retT", XX, XX, XX }, + { "les{S|}", Gv, Mp, XX }, + { "ldsS", Gv, Mp, XX }, + { "movA", Eb, Ib, XX }, + { "movQ", Ev, Iv, XX }, + /* c8 */ + { "enterT", Iw, Ib, XX }, + { "leaveT", XX, XX, XX }, + { "lretP", Iw, XX, XX }, + { "lretP", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into{|}", XX, XX, XX }, + { "iretP", XX, XX, XX }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam{|}", sIb, XX, XX }, + { "aad{|}", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopneFH", Jb, XX, loop_jcxz_flag }, + { "loopeFH", Jb, XX, loop_jcxz_flag }, + { "loopFH", Jb, XX, loop_jcxz_flag }, + { "jEcxzH", Jb, XX, loop_jcxz_flag }, + { "inB", AL, Ib, XX }, + { "inS", eAX, Ib, XX }, + { "outB", Ib, AL, XX }, + { "outS", Ib, eAX, XX }, + /* e8 */ + { "callT", Jv, XX, XX }, + { "jmpT", Jv, XX, XX }, + { "ljmp{T|}", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "inB", AL, indirDX, XX }, + { "inS", eAX, indirDX, XX }, + { "outB", indirDX, AL, XX }, + { "outS", indirDX, eAX, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew, XX }, + { "lslS", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "syscall", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "sysretP", XX, XX, XX }, + /* 08 */ + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms", XX, XX, XX }, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix. */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { "movlpX", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlpX", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklpX", XM, EX, XX }, + { "unpckhpX", XM, EX, XX }, + { "movhpX", XM, EX, SIMD_Fixup, 'l' }, + { "movhpX", EX, XM, SIMD_Fixup, 'l' }, + /* 18 */ + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 20 */ + { "movL", Rm, Cm, XX }, + { "movL", Rm, Dm, XX }, + { "movL", Cm, Rm, XX }, + { "movL", Dm, Rm, XX }, + { "movL", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "movL", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, + /* 28 */ + { "movapX", XM, EX, XX }, + { "movapX", EX, XM, XX }, + { PREGRP2 }, + { "movntpX", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomisX", XM,EX, XX }, + { "comisX", XM,EX, XX }, + /* 30 */ + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 38 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 40 */ + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, + /* 48 */ + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, + /* 50 */ + { "movmskpX", Gd, XS, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andpX", XM, EX, XX }, + { "andnpX", XM, EX, XX }, + { "orpX", XM, EX, XX }, + { "xorpX", XM, EX, XX }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { PREGRP17 }, + { PREGRP16 }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, + /* 68 */ + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { PREGRP26 }, + { PREGRP24 }, + { "movd", MX, Ed, XX }, + { PREGRP19 }, + /* 70 */ + { PREGRP22 }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, + /* 78 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP23 }, + { PREGRP20 }, + /* 80 */ + { "joH", Jv, XX, cond_jump_flag }, + { "jnoH", Jv, XX, cond_jump_flag }, + { "jbH", Jv, XX, cond_jump_flag }, + { "jaeH", Jv, XX, cond_jump_flag }, + { "jeH", Jv, XX, cond_jump_flag }, + { "jneH", Jv, XX, cond_jump_flag }, + { "jbeH", Jv, XX, cond_jump_flag }, + { "jaH", Jv, XX, cond_jump_flag }, + /* 88 */ + { "jsH", Jv, XX, cond_jump_flag }, + { "jnsH", Jv, XX, cond_jump_flag }, + { "jpH", Jv, XX, cond_jump_flag }, + { "jnpH", Jv, XX, cond_jump_flag }, + { "jlH", Jv, XX, cond_jump_flag }, + { "jgeH", Jv, XX, cond_jump_flag }, + { "jleH", Jv, XX, cond_jump_flag }, + { "jgH", Jv, XX, cond_jump_flag }, + /* 90 */ + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, + /* 98 */ + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, + /* a0 */ + { "pushT", fs, XX, XX }, + { "popT", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "btS", Ev, Gv, XX }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* a8 */ + { "pushT", gs, XX, XX }, + { "popT", gs, XX, XX }, + { "rsm", XX, XX, XX }, + { "btsS", Ev, Gv, XX }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { GRP13 }, + { "imulS", Gv, Ev, XX }, + /* b0 */ + { "cmpxchgB", Eb, Gb, XX }, + { "cmpxchgS", Ev, Gv, XX }, + { "lssS", Gv, Mp, XX }, + { "btrS", Ev, Gv, XX }, + { "lfsS", Gv, Mp, XX }, + { "lgsS", Gv, Mp, XX }, + { "movz{bR|x|bR|x}", Gv, Eb, XX }, + { "movz{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movzww ! */ + /* b8 */ + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, + { GRP8 }, + { "btcS", Ev, Gv, XX }, + { "bsfS", Gv, Ev, XX }, + { "bsrS", Gv, Ev, XX }, + { "movs{bR|x|bR|x}", Gv, Eb, XX }, + { "movs{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movsww ! */ + /* c0 */ + { "xaddB", Eb, Gb, XX }, + { "xaddS", Ev, Gv, XX }, + { PREGRP1 }, + { "movntiS", Ev, Gv, XX }, + { "pinsrw", MX, Ed, Ib }, + { "pextrw", Gd, MS, Ib }, + { "shufpX", XM, EX, Ib }, + { GRP9 }, + /* c8 */ + { "bswap", RMeAX, XX, XX }, + { "bswap", RMeCX, XX, XX }, + { "bswap", RMeDX, XX, XX }, + { "bswap", RMeBX, XX, XX }, + { "bswap", RMeSP, XX, XX }, + { "bswap", RMeBP, XX, XX }, + { "bswap", RMeSI, XX, XX }, + { "bswap", RMeDI, XX, XX }, + /* d0 */ + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "paddq", MX, EM, XX }, + { "pmullw", MX, EM, XX }, + { PREGRP21 }, + { "pmovmskb", Gd, MS, XX }, + /* d8 */ + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, + /* e0 */ + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { PREGRP15 }, + { PREGRP25 }, + /* e8 */ + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "pmuludq", MX, EM, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { PREGRP18 }, + /* f8 */ + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "psubq", MX, EM, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } +}; + +static const unsigned char onebyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ + /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_SSE_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *insn_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static unsigned char need_modrm; + +/* If we are accessing mod/rm/reg without need_modrm set, then the + values are stale. Hitting this abort likely indicates that you + need to update onebyte_has_modrm or twobyte_has_modrm. */ +#define MODRM_CHECK if (!need_modrm) abort () + +static const char **names64; +static const char **names32; +static const char **names16; +static const char **names8; +static const char **names8rex; +static const char **names_seg; +static const char **index16; + +static const char *intel_names64[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; +static const char *intel_names32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" +}; +static const char *intel_names16[] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" +}; +static const char *intel_names8[] = { + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", +}; +static const char *intel_names8rex[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" +}; +static const char *intel_names_seg[] = { + "es", "cs", "ss", "ds", "fs", "gs", "?", "?", +}; +static const char *intel_index16[] = { + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" +}; + +static const char *att_names64[] = { + "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +}; +static const char *att_names32[] = { + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" +}; +static const char *att_names16[] = { + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" +}; +static const char *att_names8[] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", +}; +static const char *att_names8rex[] = { + "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" +}; +static const char *att_names_seg[] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", +}; +static const char *att_index16[] = { + "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" +}; + +static const struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addA", Eb, Ib, XX }, + { "orA", Eb, Ib, XX }, + { "adcA", Eb, Ib, XX }, + { "sbbA", Eb, Ib, XX }, + { "andA", Eb, Ib, XX }, + { "subA", Eb, Ib, XX }, + { "xorA", Eb, Ib, XX }, + { "cmpA", Eb, Ib, XX } + }, + /* GRP1S */ + { + { "addQ", Ev, Iv, XX }, + { "orQ", Ev, Iv, XX }, + { "adcQ", Ev, Iv, XX }, + { "sbbQ", Ev, Iv, XX }, + { "andQ", Ev, Iv, XX }, + { "subQ", Ev, Iv, XX }, + { "xorQ", Ev, Iv, XX }, + { "cmpQ", Ev, Iv, XX } + }, + /* GRP1Ss */ + { + { "addQ", Ev, sIb, XX }, + { "orQ", Ev, sIb, XX }, + { "adcQ", Ev, sIb, XX }, + { "sbbQ", Ev, sIb, XX }, + { "andQ", Ev, sIb, XX }, + { "subQ", Ev, sIb, XX }, + { "xorQ", Ev, sIb, XX }, + { "cmpQ", Ev, sIb, XX } + }, + /* GRP2b */ + { + { "rolA", Eb, Ib, XX }, + { "rorA", Eb, Ib, XX }, + { "rclA", Eb, Ib, XX }, + { "rcrA", Eb, Ib, XX }, + { "shlA", Eb, Ib, XX }, + { "shrA", Eb, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, Ib, XX }, + }, + /* GRP2S */ + { + { "rolQ", Ev, Ib, XX }, + { "rorQ", Ev, Ib, XX }, + { "rclQ", Ev, Ib, XX }, + { "rcrQ", Ev, Ib, XX }, + { "shlQ", Ev, Ib, XX }, + { "shrQ", Ev, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, Ib, XX }, + }, + /* GRP2b_one */ + { + { "rolA", Eb, XX, XX }, + { "rorA", Eb, XX, XX }, + { "rclA", Eb, XX, XX }, + { "rcrA", Eb, XX, XX }, + { "shlA", Eb, XX, XX }, + { "shrA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, XX, XX }, + }, + /* GRP2S_one */ + { + { "rolQ", Ev, XX, XX }, + { "rorQ", Ev, XX, XX }, + { "rclQ", Ev, XX, XX }, + { "rcrQ", Ev, XX, XX }, + { "shlQ", Ev, XX, XX }, + { "shrQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX}, + { "sarQ", Ev, XX, XX }, + }, + /* GRP2b_cl */ + { + { "rolA", Eb, CL, XX }, + { "rorA", Eb, CL, XX }, + { "rclA", Eb, CL, XX }, + { "rcrA", Eb, CL, XX }, + { "shlA", Eb, CL, XX }, + { "shrA", Eb, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, CL, XX }, + }, + /* GRP2S_cl */ + { + { "rolQ", Ev, CL, XX }, + { "rorQ", Ev, CL, XX }, + { "rclQ", Ev, CL, XX }, + { "rcrQ", Ev, CL, XX }, + { "shlQ", Ev, CL, XX }, + { "shrQ", Ev, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, CL, XX } + }, + /* GRP3b */ + { + { "testA", Eb, Ib, XX }, + { "(bad)", Eb, XX, XX }, + { "notA", Eb, XX, XX }, + { "negA", Eb, XX, XX }, + { "mulA", Eb, XX, XX }, /* Don't print the implicit %al register, */ + { "imulA", Eb, XX, XX }, /* to distinguish these opcodes from other */ + { "divA", Eb, XX, XX }, /* mul/imul opcodes. Do the same for div */ + { "idivA", Eb, XX, XX } /* and idiv for consistency. */ + }, + /* GRP3S */ + { + { "testQ", Ev, Iv, XX }, + { "(bad)", XX, XX, XX }, + { "notQ", Ev, XX, XX }, + { "negQ", Ev, XX, XX }, + { "mulQ", Ev, XX, XX }, /* Don't print the implicit register. */ + { "imulQ", Ev, XX, XX }, + { "divQ", Ev, XX, XX }, + { "idivQ", Ev, XX, XX }, + }, + /* GRP4 */ + { + { "incA", Eb, XX, XX }, + { "decA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP5 */ + { + { "incQ", Ev, XX, XX }, + { "decQ", Ev, XX, XX }, + { "callT", indirEv, XX, XX }, + { "lcallT", indirEv, XX, XX }, + { "jmpT", indirEv, XX, XX }, + { "ljmpT", indirEv, XX, XX }, + { "pushU", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP6 */ + { + { "sldtQ", Ev, XX, XX }, + { "strQ", Ev, XX, XX }, + { "lldt", Ew, XX, XX }, + { "ltr", Ew, XX, XX }, + { "verr", Ew, XX, XX }, + { "verw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX } + }, + /* GRP7 */ + { + { "sgdtQ", M, XX, XX }, + { "sidtQ", M, XX, XX }, + { "lgdtQ", M, XX, XX }, + { "lidtQ", M, XX, XX }, + { "smswQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lmsw", Ew, XX, XX }, + { "invlpg", Ew, XX, XX }, + }, + /* GRP8 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "btQ", Ev, Ib, XX }, + { "btsQ", Ev, Ib, XX }, + { "btrQ", Ev, Ib, XX }, + { "btcQ", Ev, Ib, XX }, + }, + /* GRP9 */ + { + { "(bad)", XX, XX, XX }, + { "cmpxchg8b", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP10 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psraw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psllw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP11 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psrad", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "pslld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP12 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlq", MS, Ib, XX }, + { "psrldq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psllq", MS, Ib, XX }, + { "pslldq", MS, Ib, XX }, + }, + /* GRP13 */ + { + { "fxsave", Ev, XX, XX }, + { "fxrstor", Ev, XX, XX }, + { "ldmxcsr", Ev, XX, XX }, + { "stmxcsr", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lfence", None, XX, XX }, + { "mfence", None, XX, XX }, + { "sfence", None, XX, XX }, + /* FIXME: the sfence with memory operand is clflush! */ + }, + /* GRP14 */ + { + { "prefetchnta", Ev, XX, XX }, + { "prefetcht0", Ev, XX, XX }, + { "prefetcht1", Ev, XX, XX }, + { "prefetcht2", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRPAMD */ + { + { "prefetch", Eb, XX, XX }, + { "prefetchw", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + } +}; + +static const struct dis386 prefix_user_table[][4] = { + /* PREGRP0 */ + { + { "addps", XM, EX, XX }, + { "addss", XM, EX, XX }, + { "addpd", XM, EX, XX }, + { "addsd", XM, EX, XX }, + }, + /* PREGRP1 */ + { + { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX. */ + { "", XM, EX, OPSIMD }, + { "", XM, EX, OPSIMD }, + { "", XM, EX, OPSIMD }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", XM, EM, XX }, + { "cvtsi2ssY", XM, Ev, XX }, + { "cvtpi2pd", XM, EM, XX }, + { "cvtsi2sdY", XM, Ev, XX }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", MX, EX, XX }, + { "cvtss2siY", Gv, EX, XX }, + { "cvtpd2pi", MX, EX, XX }, + { "cvtsd2siY", Gv, EX, XX }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", MX, EX, XX }, + { "cvttss2siY", Gv, EX, XX }, + { "cvttpd2pi", MX, EX, XX }, + { "cvttsd2siY", Gv, EX, XX }, + }, + /* PREGRP5 */ + { + { "divps", XM, EX, XX }, + { "divss", XM, EX, XX }, + { "divpd", XM, EX, XX }, + { "divsd", XM, EX, XX }, + }, + /* PREGRP6 */ + { + { "maxps", XM, EX, XX }, + { "maxss", XM, EX, XX }, + { "maxpd", XM, EX, XX }, + { "maxsd", XM, EX, XX }, + }, + /* PREGRP7 */ + { + { "minps", XM, EX, XX }, + { "minss", XM, EX, XX }, + { "minpd", XM, EX, XX }, + { "minsd", XM, EX, XX }, + }, + /* PREGRP8 */ + { + { "movups", XM, EX, XX }, + { "movss", XM, EX, XX }, + { "movupd", XM, EX, XX }, + { "movsd", XM, EX, XX }, + }, + /* PREGRP9 */ + { + { "movups", EX, XM, XX }, + { "movss", EX, XM, XX }, + { "movupd", EX, XM, XX }, + { "movsd", EX, XM, XX }, + }, + /* PREGRP10 */ + { + { "mulps", XM, EX, XX }, + { "mulss", XM, EX, XX }, + { "mulpd", XM, EX, XX }, + { "mulsd", XM, EX, XX }, + }, + /* PREGRP11 */ + { + { "rcpps", XM, EX, XX }, + { "rcpss", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP12 */ + { + { "rsqrtps", XM, EX, XX }, + { "rsqrtss", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP13 */ + { + { "sqrtps", XM, EX, XX }, + { "sqrtss", XM, EX, XX }, + { "sqrtpd", XM, EX, XX }, + { "sqrtsd", XM, EX, XX }, + }, + /* PREGRP14 */ + { + { "subps", XM, EX, XX }, + { "subss", XM, EX, XX }, + { "subpd", XM, EX, XX }, + { "subsd", XM, EX, XX }, + }, + /* PREGRP15 */ + { + { "(bad)", XM, EX, XX }, + { "cvtdq2pd", XM, EX, XX }, + { "cvttpd2dq", XM, EX, XX }, + { "cvtpd2dq", XM, EX, XX }, + }, + /* PREGRP16 */ + { + { "cvtdq2ps", XM, EX, XX }, + { "cvttps2dq",XM, EX, XX }, + { "cvtps2dq",XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP17 */ + { + { "cvtps2pd", XM, EX, XX }, + { "cvtss2sd", XM, EX, XX }, + { "cvtpd2ps", XM, EX, XX }, + { "cvtsd2ss", XM, EX, XX }, + }, + /* PREGRP18 */ + { + { "maskmovq", MX, MS, XX }, + { "(bad)", XM, EX, XX }, + { "maskmovdqu", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP19 */ + { + { "movq", MX, EM, XX }, + { "movdqu", XM, EX, XX }, + { "movdqa", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP20 */ + { + { "movq", EM, MX, XX }, + { "movdqu", EX, XM, XX }, + { "movdqa", EX, XM, XX }, + { "(bad)", EX, XM, XX }, + }, + /* PREGRP21 */ + { + { "(bad)", EX, XM, XX }, + { "movq2dq", XM, MS, XX }, + { "movq", EX, XM, XX }, + { "movdq2q", MX, XS, XX }, + }, + /* PREGRP22 */ + { + { "pshufw", MX, EM, Ib }, + { "pshufhw", XM, EX, Ib }, + { "pshufd", XM, EX, Ib }, + { "pshuflw", XM, EX, Ib }, + }, + /* PREGRP23 */ + { + { "movd", Ed, MX, XX }, + { "movq", XM, EX, XX }, + { "movd", Ed, XM, XX }, + { "(bad)", Ed, XM, XX }, + }, + /* PREGRP24 */ + { + { "(bad)", MX, EX, XX }, + { "(bad)", XM, EX, XX }, + { "punpckhqdq", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP25 */ + { + { "movntq", Ev, MX, XX }, + { "(bad)", Ev, XM, XX }, + { "movntdq", Ev, XM, XX }, + { "(bad)", Ev, XM, XX }, + }, + /* PREGRP26 */ + { + { "(bad)", MX, EX, XX }, + { "(bad)", XM, EX, XX }, + { "punpcklqdq", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, +}; + +static const struct dis386 x86_64_table[][2] = { + { + { "arpl", Ew, Gw, XX }, + { "movs{||lq|xd}", Gv, Ed, XX }, + }, +}; + +#define INTERNAL_DISASSEMBLER_ERROR _("") + +static void +ckprefix () +{ + int newrex; + rex = 0; + prefixes = 0; + used_prefixes = 0; + rex_used = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + newrex = 0; + switch (*codep) + { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + if (mode_64bit) + newrex = *codep; + else + return; + break; + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADDR; + break; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; + break; + default: + return; + } + /* Rex is ignored when followed by another prefix. */ + if (rex) + { + oappend (prefix_name (rex, 0)); + oappend (" "); + } + rex = newrex; + codep++; + } +} + +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ + +static const char * +prefix_name (pref, sizeflag) + int pref; + int sizeflag; +{ + switch (pref) + { + /* REX prefixes family. */ + case 0x40: + return "rex"; + case 0x41: + return "rexZ"; + case 0x42: + return "rexY"; + case 0x43: + return "rexYZ"; + case 0x44: + return "rexX"; + case 0x45: + return "rexXZ"; + case 0x46: + return "rexXY"; + case 0x47: + return "rexXYZ"; + case 0x48: + return "rex64"; + case 0x49: + return "rex64Z"; + case 0x4a: + return "rex64Y"; + case 0x4b: + return "rex64YZ"; + case 0x4c: + return "rex64X"; + case 0x4d: + return "rex64XZ"; + case 0x4e: + return "rex64XY"; + case 0x4f: + return "rex64XYZ"; + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + if (mode_64bit) + return (sizeflag & AFLAG) ? "addr32" : "addr64"; + else + return ((sizeflag & AFLAG) && !mode_64bit) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} + +static char op1out[100], op2out[100], op3out[100]; +static int op_ad, op_index[3]; +static bfd_vma op_address[3]; +static bfd_vma op_riprel[3]; +static bfd_vma start_pc; + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +/* Here for backwards compatibility. When gdb stops using + print_insn_i386_att and print_insn_i386_intel these functions can + disappear, and print_insn_i386 be merged into print_insn. */ +int +print_insn_i386_att (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 0; + + return print_insn (pc, info); +} + +int +print_insn_i386_intel (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 1; + + return print_insn (pc, info); +} + +int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = -1; + + return print_insn (pc, info); +} + +static int +print_insn (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + const struct dis386 *dp; + int i; + int two_source_ops; + char *first, *second, *third; + int needcomma; + unsigned char uses_SSE_prefix; + int sizeflag; + /*const char *p;*/ + struct dis_private priv; + + mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax + || info->mach == bfd_mach_x86_64); + + if (intel_syntax == -1) + intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax); + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_x86_64 + || info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax) + priv.orig_sizeflag = AFLAG | DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + priv.orig_sizeflag = 0; + else + abort (); + +#if 0 + for (p = info->disassembler_options; p != NULL; ) + { + if (strncmp (p, "x86-64", 6) == 0) + { + mode_64bit = 1; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i386", 4) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i8086", 5) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = 0; + } + else if (strncmp (p, "intel", 5) == 0) + { + intel_syntax = 1; + } + else if (strncmp (p, "att", 3) == 0) + { + intel_syntax = 0; + } + else if (strncmp (p, "addr", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= AFLAG; + } + else if (strncmp (p, "data", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~DFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= DFLAG; + } + else if (strncmp (p, "suffix", 6) == 0) + priv.orig_sizeflag |= SUFFIX_ALWAYS; + + p = strchr (p, ','); + if (p != NULL) + p++; + } +#else + mode_64bit = 1; + priv.orig_sizeflag = AFLAG | DFLAG; + intel_syntax = 1; +#endif + + if (intel_syntax) + { + names64 = intel_names64; + names32 = intel_names32; + names16 = intel_names16; + names8 = intel_names8; + names8rex = intel_names8rex; + names_seg = intel_names_seg; + index16 = intel_index16; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + } + else + { + names64 = att_names64; + names32 = att_names32; + names16 = att_names16; + names8 = att_names8; + names8rex = att_names8rex; + names_seg = att_names_seg; + index16 = att_index16; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + } + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = priv.the_buffer; + codep = priv.the_buffer; + + if (_setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > priv.the_buffer) + { + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) priv.the_buffer[0]); + } + + return 1; + } + + return -1; + } + + obufp = obuf; + ckprefix (); + + insn_codep = codep; + sizeflag = priv.orig_sizeflag; + + FETCH_DATA (info, codep + 1); + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + const char *name; + + /* fwait not followed by floating point instruction. Print the + first prefix, which is probably fwait itself. */ + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + dp = &dis386_twobyte[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; + } + else + { + dp = &dis386[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + uses_SSE_prefix = 0; + } + codep++; + + if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ)) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + if (prefixes & PREFIX_LOCK) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (dp->bytemode3 != loop_jcxz_mode || intel_syntax) + { + if ((sizeflag & AFLAG) || mode_64bit) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + } + + if (!uses_SSE_prefix && (prefixes & PREFIX_DATA)) + { + sizeflag ^= DFLAG; + if (dp->bytemode3 == cond_jump_mode + && dp->bytemode1 == v_mode + && !intel_syntax) + { + if (sizeflag & DFLAG) + oappend ("data32 "); + else + oappend ("data16 "); + used_prefixes |= PREFIX_DATA; + } + } + + if (need_modrm) + { + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + } + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (sizeflag); + } + else + { + int index; + if (dp->name == NULL) + { + switch (dp->bytemode1) + { + case USE_GROUPS: + dp = &grps[dp->bytemode2][reg]; + break; + + case USE_PREFIX_USER_TABLE: + index = 0; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + index = 1; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + index = 2; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + index = 3; + } + } + dp = &prefix_user_table[dp->bytemode2][index]; + break; + + case X86_64_SPECIAL: + dp = &x86_64_table[dp->bytemode2][mode_64bit]; + break; + + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + if (putop (dp->name, sizeflag) == 0) + { + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1) (dp->bytemode1, sizeflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2) (dp->bytemode2, sizeflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3) (dp->bytemode3, sizeflag); + } + } + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + if (rex & ~rex_used) + { + const char *name; + name = prefix_name (rex | 0x40, priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s ", name); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1 && !op_riprel[0]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1 && !op_riprel[1]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1 && !op_riprel[2]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + for (i = 0; i < 3; i++) + if (op_index[i] != -1 && op_riprel[i]) + { + (*info->fprintf_func) (info->stream, " # "); + (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep + + op_address[op_index[i]]), info); + } + return codep - priv.the_buffer; +} + +static const char *float_mem[] = { + /* d8 */ + "fadd{s||s|}", + "fmul{s||s|}", + "fcom{s||s|}", + "fcomp{s||s|}", + "fsub{s||s|}", + "fsubr{s||s|}", + "fdiv{s||s|}", + "fdivr{s||s|}", + /* d9 */ + "fld{s||s|}", + "(bad)", + "fst{s||s|}", + "fstp{s||s|}", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiadd{l||l|}", + "fimul{l||l|}", + "ficom{l||l|}", + "ficomp{l||l|}", + "fisub{l||l|}", + "fisubr{l||l|}", + "fidiv{l||l|}", + "fidivr{l||l|}", + /* db */ + "fild{l||l|}", + "(bad)", + "fist{l||l|}", + "fistp{l||l|}", + "(bad)", + "fld{t||t|}", + "(bad)", + "fstp{t||t|}", + /* dc */ + "fadd{l||l|}", + "fmul{l||l|}", + "fcom{l||l|}", + "fcomp{l||l|}", + "fsub{l||l|}", + "fsubr{l||l|}", + "fdiv{l||l|}", + "fdivr{l||l|}", + /* dd */ + "fld{l||l|}", + "(bad)", + "fst{l||l|}", + "fstp{l||l|}", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fild{ll||ll|}", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 + +#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 +#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 +#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 +#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 +#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 +#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 +#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 +#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 + +static const struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi, XX }, + { "fmul", ST, STi, XX }, + { "fcom", STi, XX, XX }, + { "fcomp", STi, XX, XX }, + { "fsub", ST, STi, XX }, + { "fsubr", ST, STi, XX }, + { "fdiv", ST, STi, XX }, + { "fdivr", ST, STi, XX }, + }, + /* d9 */ + { + { "fld", STi, XX, XX }, + { "fxch", STi, XX, XX }, + { FGRPd9_2 }, + { "(bad)", XX, XX, XX }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", ST, STi, XX }, + { "fcmove", ST, STi, XX }, + { "fcmovbe",ST, STi, XX }, + { "fcmovu", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + { FGRPda_5 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* db */ + { + { "fcmovnb",ST, STi, XX }, + { "fcmovne",ST, STi, XX }, + { "fcmovnbe",ST, STi, XX }, + { "fcmovnu",ST, STi, XX }, + { FGRPdb_4 }, + { "fucomi", ST, STi, XX }, + { "fcomi", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + }, + /* dc */ + { + { "fadd", STi, ST, XX }, + { "fmul", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, +#if UNIXWARE_COMPAT + { "fsub", STi, ST, XX }, + { "fsubr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, + { "fdivr", STi, ST, XX }, +#else + { "fsubr", STi, ST, XX }, + { "fsub", STi, ST, XX }, + { "fdivr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, +#endif + }, + /* dd */ + { + { "ffree", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "fst", STi, XX, XX }, + { "fstp", STi, XX, XX }, + { "fucom", STi, XX, XX }, + { "fucomp", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* de */ + { + { "faddp", STi, ST, XX }, + { "fmulp", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { FGRPde_3 }, +#if UNIXWARE_COMPAT + { "fsubp", STi, ST, XX }, + { "fsubrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, +#else + { "fsubrp", STi, ST, XX }, + { "fsubp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, +#endif + }, + /* df */ + { + { "ffreep", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { FGRPdf_4 }, + { "fucomip",ST, STi, XX }, + { "fcomip", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + }, +}; + +static char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (sizeflag) + int sizeflag; +{ + const struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg], sizeflag); + obufp = op1out; + if (floatop == 0xdb) + OP_E (x_mode, sizeflag); + else if (floatop == 0xdd) + OP_E (d_mode, sizeflag); + else + OP_E (v_mode, sizeflag); + return; + } + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm], sizeflag); + + /* Instruction fnstsw is only one with strange arg. */ + if (floatop == 0xdf && codep[-1] == 0xe0) + strcpy (op1out, names16[0]); + } + else + { + putop (dp->name, sizeflag); + + obufp = op1out; + if (dp->op1) + (*dp->op1) (dp->bytemode1, sizeflag); + obufp = op2out; + if (dp->op2) + (*dp->op2) (dp->bytemode2, sizeflag); + } +} + +static void +OP_ST (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + oappend ("%st"); +} + +static void +OP_STi (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf + intel_syntax); +} + +/* Capital letters in template are macros. */ +static int +putop (template, sizeflag) + const char *template; + int sizeflag; +{ + const char *p; + int alt; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case '{': + alt = 0; + if (intel_syntax) + alt += 1; + if (mode_64bit) + alt += 2; + while (alt != 0) + { + while (*++p != '|') + { + if (*p == '}') + { + /* Alternative not valid. */ + strcpy (obuf, "(bad)"); + obufp = obuf + 5; + return 1; + } + else if (*p == '\0') + abort (); + } + alt--; + } + break; + case '|': + while (*++p != '}') + { + if (*p == '\0') + abort (); + } + break; + case '}': + break; + case 'A': + if (intel_syntax) + break; + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; + break; + case 'E': /* For jcxz/jecxz */ + if (mode_64bit) + { + if (sizeflag & AFLAG) + *obufp++ = 'r'; + else + *obufp++ = 'e'; + } + else + if (sizeflag & AFLAG) + *obufp++ = 'e'; + used_prefixes |= (prefixes & PREFIX_ADDR); + break; + case 'F': + if (intel_syntax) + break; + if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & AFLAG) + *obufp++ = mode_64bit ? 'q' : 'l'; + else + *obufp++ = mode_64bit ? 'l' : 'w'; + used_prefixes |= (prefixes & PREFIX_ADDR); + } + break; + case 'H': + if (intel_syntax) + break; + if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS + || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) + { + used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); + *obufp++ = ','; + *obufp++ = 'p'; + if (prefixes & PREFIX_DS) + *obufp++ = 't'; + else + *obufp++ = 'n'; + } + break; + case 'L': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'O': + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + *obufp++ = 'o'; + else + *obufp++ = 'd'; + break; + case 'T': + if (intel_syntax) + break; + if (mode_64bit) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) + || (rex & REX_MODE64) + || (sizeflag & SUFFIX_ALWAYS)) + { + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'U': + if (intel_syntax) + break; + if (mode_64bit) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'Q': + if (intel_syntax) + break; + USED_REX (REX_MODE64); + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'R': + USED_REX (REX_MODE64); + if (intel_syntax) + { + if (rex & REX_MODE64) + { + *obufp++ = 'q'; + *obufp++ = 't'; + } + else if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'q'; + } + else + { + *obufp++ = 'w'; + *obufp++ = 'd'; + } + } + else + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + if (!(rex & REX_MODE64)) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'S': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'X': + if (prefixes & PREFIX_DATA) + *obufp++ = 'd'; + else + *obufp++ = 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'Y': + if (intel_syntax) + break; + if (rex & REX_MODE64) + { + USED_REX (REX_MODE64); + *obufp++ = 'q'; + } + break; + /* implicit operand size 'l' for i386 or 'q' for x86-64 */ + case 'W': + /* operand size flag for cwtl, cbtw */ + USED_REX (0); + if (rex) + *obufp++ = 'l'; + else if (sizeflag & DFLAG) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + if (intel_syntax) + { + if (rex) + { + *obufp++ = 'q'; + *obufp++ = 'e'; + } + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'e'; + } + else + { + *obufp++ = 'w'; + } + } + if (!rex) + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + } + *obufp = 0; + return 0; +} + +static void +oappend (s) + const char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); +} + +static void +append_seg () +{ + if (prefixes & PREFIX_CS) + { + used_prefixes |= PREFIX_CS; + oappend ("%cs:" + intel_syntax); + } + if (prefixes & PREFIX_DS) + { + used_prefixes |= PREFIX_DS; + oappend ("%ds:" + intel_syntax); + } + if (prefixes & PREFIX_SS) + { + used_prefixes |= PREFIX_SS; + oappend ("%ss:" + intel_syntax); + } + if (prefixes & PREFIX_ES) + { + used_prefixes |= PREFIX_ES; + oappend ("%es:" + intel_syntax); + } + if (prefixes & PREFIX_FS) + { + used_prefixes |= PREFIX_FS; + oappend ("%fs:" + intel_syntax); + } + if (prefixes & PREFIX_GS) + { + used_prefixes |= PREFIX_GS; + oappend ("%gs:" + intel_syntax); + } +} + +static void +OP_indirE (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); +} + +static void +print_operand_value (buf, hex, disp) + char *buf; + int hex; + bfd_vma disp; +{ + if (mode_64bit) + { + if (hex) + { + char tmp[30]; + int i; + buf[0] = '0'; + buf[1] = 'x'; + sprintf_vma (tmp, disp); + for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); + strcpy (buf + 2, tmp + i); + } + else + { + bfd_signed_vma v = disp; + char tmp[30]; + int i; + if (v < 0) + { + *(buf++) = '-'; + v = -disp; + /* Check for possible overflow on 0x8000000000000000. */ + if (v < 0) + { + strcpy (buf, "9223372036854775808"); + return; + } + } + if (!v) + { + strcpy (buf, "0"); + return; + } + + i = 0; + tmp[29] = 0; + while (v) + { + tmp[28 - i] = (v % 10) + '0'; + v /= 10; + i++; + } + strcpy (buf, tmp + 29 - i); + } + } + else + { + if (hex) + sprintf (buf, "0x%x", (unsigned int) disp); + else + sprintf (buf, "%d", (int) disp); + } +} + +static void +OP_E (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_vma disp; + int add = 0; + int riprel = 0; + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add += 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + USED_REX (0); + if (rex) + oappend (names8rex[rm + add]); + else + oappend (names8[rm + add]); + break; + case w_mode: + oappend (names16[rm + add]); + break; + case d_mode: + oappend (names32[rm + add]); + break; + case q_mode: + oappend (names64[rm + add]); + break; + case m_mode: + if (mode_64bit) + oappend (names64[rm + add]); + else + oappend (names32[rm + add]); + break; + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + oappend (names64[rm + add]); + else if (sizeflag & DFLAG) + oappend (names32[rm + add]); + else + oappend (names16[rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + if (!(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */) + && !(codep[-2] == 0xAE && codep[-1] == 0xF0 /* mfence */) + && !(codep[-2] == 0xAE && codep[-1] == 0xe8 /* lfence */)) + BadOp (); /* bad sfence,lea,lds,les,lfs,lgs,lss modrm */ + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + return; + } + + disp = 0; + append_seg (); + + if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */ + { + int havesib; + int havebase; + int base; + int index = 0; + int scale = 0; + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + USED_REX (REX_EXTY); + USED_REX (REX_EXTZ); + if (rex & REX_EXTY) + index += 8; + if (rex & REX_EXTZ) + base += 8; + codep++; + } + + switch (mod) + { + case 0: + if ((base & 7) == 5) + { + havebase = 0; + if (mode_64bit && !havesib && (sizeflag & AFLAG)) + riprel = 1; + disp = get32s (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32s (); + break; + } + + if (!intel_syntax) + if (mod != 0 || (base & 7) == 5) + { + print_operand_value (scratchbuf, !riprel, disp); + oappend (scratchbuf); + if (riprel) + { + set_op (disp, 1); + oappend ("(%rip)"); + } + } + + if (havebase || (havesib && (index != 4 || scale != 0))) + { + if (intel_syntax) + { + switch (bytemode) + { + case b_mode: + oappend ("BYTE PTR "); + break; + case w_mode: + oappend ("WORD PTR "); + break; + case v_mode: + oappend ("DWORD PTR "); + break; + case d_mode: + oappend ("QWORD PTR "); + break; + case m_mode: + if (mode_64bit) + oappend ("DWORD PTR "); + else + oappend ("QWORD PTR "); + break; + case x_mode: + oappend ("XWORD PTR "); + break; + default: + break; + } + } + *obufp++ = open_char; + if (intel_syntax && riprel) + oappend ("rip + "); + *obufp = '\0'; + USED_REX (REX_EXTZ); + if (!havesib && (rex & REX_EXTZ)) + base += 8; + if (havebase) + oappend (mode_64bit && (sizeflag & AFLAG) + ? names64[base] : names32[base]); + if (havesib) + { + if (index != 4) + { + if (intel_syntax) + { + if (havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + sprintf (scratchbuf, "%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); + } + else + sprintf (scratchbuf, ",%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); + oappend (scratchbuf); + } + if (!intel_syntax + || (intel_syntax + && bytemode != b_mode + && bytemode != w_mode + && bytemode != v_mode)) + { + *obufp++ = scale_char; + *obufp = '\0'; + sprintf (scratchbuf, "%d", 1 << scale); + oappend (scratchbuf); + } + } + if (intel_syntax) + if (mod != 0 || (base & 7) == 5) + { + /* Don't print zero displacements. */ + if (disp != 0) + { + if ((bfd_signed_vma) disp > 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + + print_operand_value (scratchbuf, 0, disp); + oappend (scratchbuf); + } + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (mod != 0 || (base & 7) == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, 1, disp); + oappend (scratchbuf); + } + } + } + else + { /* 16 bit address mode */ + switch (mod) + { + case 0: + if ((rm & 7) == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (!intel_syntax) + if (mod != 0 || (rm & 7) == 6) + { + print_operand_value (scratchbuf, 0, disp); + oappend (scratchbuf); + } + + if (mod != 0 || (rm & 7) != 6) + { + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[rm + add]); + *obufp++ = close_char; + *obufp = '\0'; + } + } +} + +static void +OP_G (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add += 8; + switch (bytemode) + { + case b_mode: + USED_REX (0); + if (rex) + oappend (names8rex[reg + add]); + else + oappend (names8[reg + add]); + break; + case w_mode: + oappend (names16[reg + add]); + break; + case d_mode: + oappend (names32[reg + add]); + break; + case q_mode: + oappend (names64[reg + add]); + break; + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + oappend (names64[reg + add]); + else if (sizeflag & DFLAG) + oappend (names32[reg + add]); + else + oappend (names16[reg + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } +} + +static bfd_vma +get64 () +{ + bfd_vma x; +#ifdef BFD64 + unsigned int a; + unsigned int b; + + FETCH_DATA (the_info, codep + 8); + a = *codep++ & 0xff; + a |= (*codep++ & 0xff) << 8; + a |= (*codep++ & 0xff) << 16; + a |= (*codep++ & 0xff) << 24; + b = *codep++ & 0xff; + b |= (*codep++ & 0xff) << 8; + b |= (*codep++ & 0xff) << 16; + b |= (*codep++ & 0xff) << 24; + x = a + ((bfd_vma) b << 32); +#else + abort (); + x = 0; +#endif + return x; +} + +static bfd_signed_vma +get32 () +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + return x; +} + +static bfd_signed_vma +get32s () +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + + x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); + + return x; +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return x; +} + +static void +set_op (op, riprel) + bfd_vma op; + int riprel; +{ + op_index[op_ad] = op_ad; + if (mode_64bit) + { + op_address[op_ad] = op; + op_riprel[op_ad] = riprel; + } + else + { + /* Mask to get a 32-bit address. */ + op_address[op_ad] = op & 0xffffffff; + op_riprel[op_ad] = riprel & 0xffffffff; + } +} + +static void +OP_REG (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + int add = 0; + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + switch (code) + { + case indir_dx_reg: + if (intel_syntax) + s = "[dx]"; + else + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg + add]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg + add]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg + add]; + else + s = names8[code - al_reg]; + break; + case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: + case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: + if (mode_64bit) + { + s = names64[code - rAX_reg + add]; + break; + } + code += eAX_reg - rAX_reg; + /* Fall through. */ + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + s = names64[code - eAX_reg + add]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg + add]; + else + s = names16[code - eAX_reg + add]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_IMREG (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + + switch (code) + { + case indir_dx_reg: + if (intel_syntax) + s = "[dx]"; + else + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg]; + else + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + s = names64[code - eAX_reg]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_I (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case q_mode: + if (mode_64bit) + { + op = get32s (); + break; + } + /* Fall through. */ + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_I64 (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + if (!mode_64bit) + { + OP_I (bytemode, sizeflag); + return; + } + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get64 (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_sI (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + mask = 0xffffffff; + break; + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32s (); + mask = 0xffffffff; + } + else + { + mask = 0xffffffff; + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + mask = 0xffffffff; + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_J (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_vma disp; + bfd_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if (sizeflag & DFLAG) + disp = get32s (); + else + { + disp = get16 (); + /* For some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp, 0); + print_operand_value (scratchbuf, 1, disp); + oappend (scratchbuf); +} + +static void +OP_SEG (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + oappend (names_seg[reg]); +} + +static void +OP_DIR (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag; +{ + int seg, offset; + + if (sizeflag & DFLAG) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + if (intel_syntax) + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + else + sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); +} + +static void +OP_OFF (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag; +{ + bfd_vma off; + + append_seg (); + + if ((sizeflag & AFLAG) || mode_64bit) + off = get32 (); + else + off = get16 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, 1, off); + oappend (scratchbuf); +} + +static void +OP_OFF64 (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + bfd_vma off; + + if (!mode_64bit) + { + OP_OFF (bytemode, sizeflag); + return; + } + + append_seg (); + + off = get64 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, 1, off); + oappend (scratchbuf); +} + +static void +ptr_reg (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + if (intel_syntax) + oappend ("["); + else + oappend ("("); + + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + { + if (!(sizeflag & AFLAG)) + s = names32[code - eAX_reg]; + else + s = names64[code - eAX_reg]; + } + else if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + if (intel_syntax) + oappend ("]"); + else + oappend (")"); +} + +static void +OP_ESreg (code, sizeflag) + int code; + int sizeflag; +{ + oappend ("%es:" + intel_syntax); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (code, sizeflag) + int code; + int sizeflag; +{ + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_seg (); + ptr_reg (code, sizeflag); +} + +static void +OP_C (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%cr%d", reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_D (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + if (intel_syntax) + sprintf (scratchbuf, "db%d", reg + add); + else + sprintf (scratchbuf, "%%db%d", reg + add); + oappend (scratchbuf); +} + +static void +OP_T (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_Rd (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_MMX (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + sprintf (scratchbuf, "%%xmm%d", reg + add); + else + sprintf (scratchbuf, "%%mm%d", reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_XMM (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%xmm%d", reg + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EM (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int add = 0; + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + sprintf (scratchbuf, "%%xmm%d", rm + add); + else + sprintf (scratchbuf, "%%mm%d", rm + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_EX (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int add = 0; + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + sprintf (scratchbuf, "%%xmm%d", rm + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_XS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EX (bytemode, sizeflag); + else + BadOp (); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen (obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp (); + } +} + +static const char *simd_cmp_op[] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen (obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + char suffix1 = 'p', suffix2 = 's'; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + suffix1 = 's'; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + suffix2 = 'd'; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + suffix1 = 's', suffix2 = 'd'; + } + } + sprintf (scratchbuf, "cmp%s%c%c", + simd_cmp_op[cmp_type], suffix1, suffix2); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp (); + } +} + +static void +SIMD_Fixup (extrachar, sizeflag) + int extrachar; + int sizeflag ATTRIBUTE_UNUSED; +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (mod == 3) + { + char *p = obuf + strlen (obuf); + *(p + 1) = '\0'; + *p = *(p - 1); + *(p - 1) = *(p - 2); + *(p - 2) = *(p - 3); + *(p - 3) = extrachar; + } +} + +static void +BadOp (void) +{ + /* Throw away prefixes and 1st. opcode byte. */ + codep = insn_codep + 1; + oappend ("(bad)"); +} diff --git a/reactos/ntoskrnl/kdbg/amd64/kdb.c b/reactos/ntoskrnl/kdbg/amd64/kdb.c new file mode 100644 index 00000000000..239902f3234 --- /dev/null +++ b/reactos/ntoskrnl/kdbg/amd64/kdb.c @@ -0,0 +1,111 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/kdbg/amd64/kdb.c + * PURPOSE: Kernel Debugger + * PROGRAMMERS: + */ + + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +ULONG +NTAPI +KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame) +{ + return TrapFrame->Rsp; +} + +VOID +NTAPI +KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame, + IN ULONG_PTR Esp) +{ + KIRQL OldIrql; + ULONG Previous; + + /* Raise to APC_LEVEL if needed */ + OldIrql = KeGetCurrentIrql(); + if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); + + /* Get the old ESP */ + Previous = KiEspFromTrapFrame(TrapFrame); + + /* Check if this is user-mode */ + if ((TrapFrame->SegCs & MODE_MASK)) + { + /* Write it directly */ + TrapFrame->Rsp = Esp; + } + else + { + /* Don't allow ESP to be lowered, this is illegal */ + if (Esp < Previous) KeBugCheckEx(SET_OF_INVALID_CONTEXT, + Esp, + Previous, + (ULONG_PTR)TrapFrame, + 0); + + /* Create an edit frame, check if it was alrady */ + if (!(TrapFrame->SegCs & FRAME_EDITED)) + { + /* Update the value */ + TrapFrame->Rsp = Esp; + } + else + { + /* Check if ESP changed */ + if (Previous != Esp) + { + /* Save CS */ + TrapFrame->SegCs &= ~FRAME_EDITED; + + /* Save ESP */ + TrapFrame->Rsp = Esp; + } + } + } + + /* Restore IRQL */ + if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); + +} + +ULONG +NTAPI +KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame) +{ + if (TrapFrame->SegCs & MODE_MASK) + { + /* User mode, return the User SS */ + return TrapFrame->SegSs | RPL_MASK; + } + else + { + /* Kernel mode */ + return KGDT64_SYS_TSS; + } +} + +VOID +NTAPI +KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame, + IN ULONG Ss) +{ + /* Remove the high-bits */ + Ss &= 0xFFFF; + + if (TrapFrame->SegCs & MODE_MASK) + { + /* Usermode, save the User SS */ + TrapFrame->SegSs = Ss | RPL_MASK; + } + +} + + + diff --git a/reactos/ntoskrnl/kdbg/amd64/kdb_help.S b/reactos/ntoskrnl/kdbg/amd64/kdb_help.S new file mode 100644 index 00000000000..eb777010513 --- /dev/null +++ b/reactos/ntoskrnl/kdbg/amd64/kdb_help.S @@ -0,0 +1,152 @@ +#include +#include + +.globl KdbEnter +KdbEnter: + + /* save flags */ + pushfq +// .pushreg ? + + /* Make room for a KTRAP_FRAME */ + sub rsp, SIZE_KTRAP_FRAME +// .allocstack SIZE_KTRAP_FRAME + + /* Save rbp */ + mov [rsp + KTRAP_FRAME_Rbp], rbp + + /* Save non-volatile registers */ + mov [rsp + KTRAP_FRAME_Rbx], rbx + mov [rsp + KTRAP_FRAME_Rdi], rdi + mov [rsp + KTRAP_FRAME_Rsi], rsi + + /* Save volatile registers */ + mov [rsp + KTRAP_FRAME_Rax], rax + mov [rsp + KTRAP_FRAME_Rcx], rcx + mov [rsp + KTRAP_FRAME_Rdx], rdx + mov [rsp + KTRAP_FRAME_R8], r8 + mov [rsp + KTRAP_FRAME_R9], r9 + mov [rsp + KTRAP_FRAME_R10], r10 + mov [rsp + KTRAP_FRAME_R11], r11 + + /* Save xmm registers */ + movdqa [rsp + KTRAP_FRAME_Xmm0], xmm0 + movdqa [rsp + KTRAP_FRAME_Xmm1], xmm1 + movdqa [rsp + KTRAP_FRAME_Xmm2], xmm2 + movdqa [rsp + KTRAP_FRAME_Xmm3], xmm3 + movdqa [rsp + KTRAP_FRAME_Xmm4], xmm4 + movdqa [rsp + KTRAP_FRAME_Xmm5], xmm5 + + /* Save cs and previous mode */ + mov ax, cs + mov [rsp + KTRAP_FRAME_SegCs], ax + and ax, 1 + mov [rsp + KTRAP_FRAME_PreviousMode], al + + /* Save segment selectors */ + mov ax, ds + mov [rsp + KTRAP_FRAME_SegDs], ax + mov ax, es + mov [rsp + KTRAP_FRAME_SegEs], ax + mov ax, fs + mov [rsp + KTRAP_FRAME_SegFs], ax + mov ax, gs + mov [rsp + KTRAP_FRAME_SegGs], ax + + /* Save previous irql */ + mov rax, cr8 + mov [rsp + KTRAP_FRAME_PreviousIrql], al + + /* Save debug registers */ + mov rax, dr0 + mov [rsp + KTRAP_FRAME_Dr0], rax + mov rax, dr1 + mov [rsp + KTRAP_FRAME_Dr1], rax + mov rax, dr2 + mov [rsp + KTRAP_FRAME_Dr2], rax + mov rax, dr3 + mov [rsp + KTRAP_FRAME_Dr3], rax + mov rax, dr6 + mov [rsp + KTRAP_FRAME_Dr6], rax + mov rax, dr7 + mov [rsp + KTRAP_FRAME_Dr7], rax + + /* Point rbp, where rsp was before */ + lea rbp, [rsp + SIZE_KTRAP_FRAME] + mov [rsp + KTRAP_FRAME_Rsp], rbp + + /* Store the EFLAGS we previously pushed on the stack */ + mov rax, [rbp + 8] + mov [rsp + KTRAP_FRAME_EFlags], rax + + /* Get RIP from the stack */ + mov rax, [rbp + 16] + mov [rsp + KTRAP_FRAME_Rip], rax + + /* Make sure the direction flag is cleared */ + cld + + /* Clear all breakpoint enables in dr7. */ + mov rax, dr7 + and rax, 0xFFFF0000 + mov dr7, rax + + /* Call KDB */ + mov byte ptr [rsp + KTRAP_FRAME_P5], 1 /* FirstChance */ + mov r9, rsp /* Pointer to the trap frame */ + mov r8, 0 /* Context */ + mov dl, 0 /* PreviousMode (KernelMode) */ + mov rcx, 0 /* ExceptionRecord */ + call KdbEnterDebuggerException + + /* Restore segment selectors */ + mov ax, [rsp + KTRAP_FRAME_SegDs] + mov ds, ax + mov ax, [rsp + KTRAP_FRAME_SegEs] + mov es, ax + mov ax, [rsp + KTRAP_FRAME_SegFs] + mov fs, ax + + /* Restore non-volatile registers */ + mov rbx, [rsp + KTRAP_FRAME_Rbx] + mov rdi, [rsp + KTRAP_FRAME_Rdi] + mov rsi, [rsp + KTRAP_FRAME_Rsi] + + /* Restore volatile registers */ + mov rax, [rsp + KTRAP_FRAME_Rax] + mov rcx, [rsp + KTRAP_FRAME_Rcx] + mov rdx, [rsp + KTRAP_FRAME_Rdx] + mov r8, [rsp + KTRAP_FRAME_R8] + mov r9, [rsp + KTRAP_FRAME_R9] + mov r10, [rsp + KTRAP_FRAME_R10] + mov r11, [rsp + KTRAP_FRAME_R11] + + /* Restore RSP */ + mov rsp, [rsp + KTRAP_FRAME_Rsp] + + /* Restore EFLAGS */ + popfq + + ret + +.globl KdbpStackSwitchAndCall +KdbpStackSwitchAndCall: + + /* Save old stack */ + mov rax, rsp + + /* Set new stack */ + mov rsp, rcx + + /* Save old stack on new stack */ + push rax + + /* Call function */ + call rdx + + /* Restire old stack */ + pop rax + mov rsp, rax + + /* Return */ + ret \ No newline at end of file diff --git a/reactos/ntoskrnl/ke/amd64/boot.S b/reactos/ntoskrnl/ke/amd64/boot.S new file mode 100644 index 00000000000..f1715c6663e --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/boot.S @@ -0,0 +1,64 @@ +/* + * FILE: ntoskrnl/ke/i386/boot.S + * COPYRIGHT: See COPYING in the top level directory + * PURPOSE: FreeLDR Wrapper Bootstrap Code and Bootstrap Trampoline + * PROGRAMMERs: Alex Ionescu (alex@relsoft.net) + * Thomas Weidenmueller + */ + +/* INCLUDES ******************************************************************/ + +#include +#include + +EXTERN KiInitializeKernelAndGotoIdleLoop:PROC + +/* GLOBALS *******************************************************************/ + + +/* FUNCTIONS *****************************************************************/ + +.code64 +.text + +/** + * VOID + * KiSetupStackAndInitializeKernel( + * IN PKPROCESS InitProcess, + * IN PKTHREAD InitThread, + * IN PVOID IdleStack, + * IN PKPRCB Prcb, + * IN CCHAR Number, + * IN PLOADER_PARAMETER_BLOCK LoaderBlock) + */ +PUBLIC KiSetupStackAndInitializeKernel +.PROC KiSetupStackAndInitializeKernel + + /* Save current stack */ + mov rsi, rsp + + /* Setup the new stack */ + mov ax, HEX(18) + mov ss, ax + mov rsp, r8 + sub rsp, HEX(300) // FIXME + + /* Copy stack parameters to the new stack */ + sub rsp, HEX(38) + .ENDPROLOG + + mov rdi, rsp + movsq + movsq + movsq + movsq + movsq + movsq + movsq + + jmp KiInitializeKernelAndGotoIdleLoop + +.ENDP KiSetupStackAndInitializeKernel + +END + diff --git a/reactos/ntoskrnl/ke/amd64/context.c b/reactos/ntoskrnl/ke/amd64/context.c new file mode 100644 index 00000000000..239a697e660 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/context.c @@ -0,0 +1,250 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * PURPOSE: CONTEXT related functions + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include + +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +KeContextToTrapFrame(IN PCONTEXT Context, + IN OUT PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PKTRAP_FRAME TrapFrame, + IN ULONG ContextFlags, + IN KPROCESSOR_MODE PreviousMode) +{ + KIRQL OldIrql; + + /* Do this at APC_LEVEL */ + OldIrql = KeGetCurrentIrql(); + if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); + + /* Handle integer registers */ + if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + TrapFrame->Rax = Context->Rax; + TrapFrame->Rbx = Context->Rbx; + TrapFrame->Rcx = Context->Rcx; + TrapFrame->Rdx = Context->Rdx; + TrapFrame->Rsi = Context->Rsi; + TrapFrame->Rdi = Context->Rdi; + TrapFrame->Rbp = Context->Rbp; + TrapFrame->R8 = Context->R8; + TrapFrame->R9 = Context->R9; + TrapFrame->R10 = Context->R10; + TrapFrame->R11 = Context->R11; + ExceptionFrame->R12 = Context->R12; + ExceptionFrame->R13 = Context->R13; + ExceptionFrame->R14 = Context->R14; + ExceptionFrame->R15 = Context->R15; + } + + /* Handle floating point registers */ + if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) == + CONTEXT_FLOATING_POINT) && (Context->SegCs & MODE_MASK)) + { + TrapFrame->Xmm0 = Context->Xmm0; + TrapFrame->Xmm1 = Context->Xmm1; + TrapFrame->Xmm2 = Context->Xmm2; + TrapFrame->Xmm3 = Context->Xmm3; + TrapFrame->Xmm4 = Context->Xmm4; + TrapFrame->Xmm5 = Context->Xmm5; + ExceptionFrame->Xmm6 = Context->Xmm6; + ExceptionFrame->Xmm7 = Context->Xmm7; + ExceptionFrame->Xmm8 = Context->Xmm8; + ExceptionFrame->Xmm9 = Context->Xmm9; + ExceptionFrame->Xmm10 = Context->Xmm10; + ExceptionFrame->Xmm11 = Context->Xmm11; + ExceptionFrame->Xmm12 = Context->Xmm12; + ExceptionFrame->Xmm13 = Context->Xmm13; + ExceptionFrame->Xmm14 = Context->Xmm14; + ExceptionFrame->Xmm15 = Context->Xmm15; + } + + /* Handle control registers */ + if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + /* Check if this was a Kernel Trap */ + if (Context->SegCs == KGDT64_R0_CODE) + { + /* Set valid selectors */ + TrapFrame->SegCs = KGDT64_R0_CODE; + TrapFrame->SegSs = KGDT64_R0_DATA; + } + else + { + /* Copy selectors */ + TrapFrame->SegCs = Context->SegCs; + TrapFrame->SegSs = Context->SegSs; + } + + /* RIP, RSP, EFLAGS */ + TrapFrame->Rip = Context->Rip; + TrapFrame->Rsp = Context->Rsp; + TrapFrame->EFlags = Context->EFlags; + } + + /* Handle segment selectors */ + if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) + { + /* Check if this was a Kernel Trap */ + if (Context->SegCs == KGDT64_R0_CODE) + { + /* Set valid selectors */ + TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK; + TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK; + } + else + { + /* Copy selectors */ + TrapFrame->SegDs = Context->SegDs; + TrapFrame->SegEs = Context->SegEs; + TrapFrame->SegFs = Context->SegFs; + TrapFrame->SegGs = Context->SegGs; + } + } + + /* Handle debug registers */ + if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == + CONTEXT_DEBUG_REGISTERS) + { + /* Copy the debug registers */ + TrapFrame->Dr0 = Context->Dr0; + TrapFrame->Dr1 = Context->Dr1; + TrapFrame->Dr2 = Context->Dr2; + TrapFrame->Dr3 = Context->Dr3; + TrapFrame->Dr6 = Context->Dr6; + TrapFrame->Dr7 = Context->Dr7; + } + + /* Restore IRQL */ + if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); +} + +VOID +NTAPI +KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PCONTEXT Context) +{ + KIRQL OldIrql; + + /* Do this at APC_LEVEL */ + OldIrql = KeGetCurrentIrql(); + if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); + + /* Handle integer registers */ + if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + Context->Rax = TrapFrame->Rax; + Context->Rbx = TrapFrame->Rbx; + Context->Rcx = TrapFrame->Rcx; + Context->Rdx = TrapFrame->Rdx; + Context->Rsi = TrapFrame->Rsi; + Context->Rdi = TrapFrame->Rdi; + Context->Rbp = TrapFrame->Rbp; + Context->R8 = TrapFrame->R8; + Context->R9 = TrapFrame->R9; + Context->R10 = TrapFrame->R10; + Context->R11 = TrapFrame->R11; + Context->R12 = ExceptionFrame->R12; + Context->R13 = ExceptionFrame->R13; + Context->R14 = ExceptionFrame->R14; + Context->R15 = ExceptionFrame->R15; + } + + /* Handle floating point registers */ + if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) == + CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK)) + { + Context->Xmm0 = TrapFrame->Xmm0; + Context->Xmm1 = TrapFrame->Xmm1; + Context->Xmm2 = TrapFrame->Xmm2; + Context->Xmm3 = TrapFrame->Xmm3; + Context->Xmm4 = TrapFrame->Xmm4; + Context->Xmm5 = TrapFrame->Xmm5; + Context->Xmm6 = ExceptionFrame->Xmm6; + Context->Xmm7 = ExceptionFrame->Xmm7; + Context->Xmm8 = ExceptionFrame->Xmm8; + Context->Xmm9 = ExceptionFrame->Xmm9; + Context->Xmm10 = ExceptionFrame->Xmm10; + Context->Xmm11 = ExceptionFrame->Xmm11; + Context->Xmm12 = ExceptionFrame->Xmm12; + Context->Xmm13 = ExceptionFrame->Xmm13; + Context->Xmm14 = ExceptionFrame->Xmm14; + Context->Xmm15 = ExceptionFrame->Xmm15; + } + + /* Handle control registers */ + if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + /* Check if this was a Kernel Trap */ + if (TrapFrame->SegCs == KGDT64_R0_CODE) + { + /* Set valid selectors */ + Context->SegCs = KGDT64_R0_CODE; + Context->SegSs = KGDT64_R0_DATA; + } + else + { + /* Copy selectors */ + Context->SegCs = TrapFrame->SegCs; + Context->SegSs = TrapFrame->SegSs; + } + + /* Copy RIP, RSP, EFLAGS */ + Context->Rip = TrapFrame->Rip; + Context->Rsp = TrapFrame->Rsp; + Context->EFlags = TrapFrame->EFlags; + } + + /* Handle segment selectors */ + if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) + { + /* Check if this was a Kernel Trap */ + if (TrapFrame->SegCs == KGDT64_R0_CODE) + { + /* Set valid selectors */ + Context->SegDs = KGDT64_R3_DATA | RPL_MASK; + Context->SegEs = KGDT64_R3_DATA | RPL_MASK; + Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK; + Context->SegGs = KGDT64_R3_DATA | RPL_MASK; + } + else + { + /* Copy selectors */ + Context->SegDs = TrapFrame->SegDs; + Context->SegEs = TrapFrame->SegEs; + Context->SegFs = TrapFrame->SegFs; + Context->SegGs = TrapFrame->SegGs; + } + } + + /* Handle debug registers */ + if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == + CONTEXT_DEBUG_REGISTERS) + { + /* Copy the debug registers */ + Context->Dr0 = TrapFrame->Dr0; + Context->Dr1 = TrapFrame->Dr1; + Context->Dr2 = TrapFrame->Dr2; + Context->Dr3 = TrapFrame->Dr3; + Context->Dr6 = TrapFrame->Dr6; + Context->Dr7 = TrapFrame->Dr7; + } + + /* Restore IRQL */ + if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); +} + diff --git a/reactos/ntoskrnl/ke/amd64/cpu.c b/reactos/ntoskrnl/ke/amd64/cpu.c new file mode 100644 index 00000000000..90a6b2c0641 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/cpu.c @@ -0,0 +1,589 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ke/amd64/cpu.c + * PURPOSE: Routines for CPU-level support + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FIXME: Local EFLAGS defines not used anywhere else */ +#define EFLAGS_IOPL 0x3000 +#define EFLAGS_NF 0x4000 +#define EFLAGS_RF 0x10000 +#define EFLAGS_ID 0x200000 + +/* GLOBALS *******************************************************************/ + +/* The Boot TSS */ +KTSS64 KiBootTss; + +/* CPU Features and Flags */ +ULONG KeI386CpuType; +ULONG KeI386CpuStep; +ULONG KeProcessorArchitecture; +ULONG KeProcessorLevel; +ULONG KeProcessorRevision; +ULONG KeFeatureBits; +ULONG KeI386MachineType; +ULONG KeI386NpxPresent = 1; +ULONG KeLargestCacheLine = 0x40; +ULONG KiDmaIoCoherency = 0; +CHAR KeNumberProcessors = 0; +KAFFINITY KeActiveProcessors = 1; +BOOLEAN KiI386PentiumLockErrataPresent; +BOOLEAN KiSMTProcessorsPresent; + +/* Freeze data */ +KIRQL KiOldIrql; +ULONG KiFreezeFlag; + +/* Flush data */ +volatile LONG KiTbFlushTimeStamp; + +/* CPU Signatures */ +static const CHAR CmpIntelID[] = "GenuineIntel"; +static const CHAR CmpAmdID[] = "AuthenticAMD"; +static const CHAR CmpCyrixID[] = "CyrixInstead"; +static const CHAR CmpTransmetaID[] = "GenuineTMx86"; +static const CHAR CmpCentaurID[] = "CentaurHauls"; +static const CHAR CmpRiseID[] = "RiseRiseRise"; + +/* SUPPORT ROUTINES FOR MSVC COMPATIBILITY ***********************************/ + +VOID +NTAPI +CPUID(IN ULONG InfoType, + OUT PULONG CpuInfoEax, + OUT PULONG CpuInfoEbx, + OUT PULONG CpuInfoEcx, + OUT PULONG CpuInfoEdx) +{ + ULONG CpuInfo[4]; + + /* Perform the CPUID Operation */ + __cpuid((int*)CpuInfo, InfoType); + + /* Return the results */ + *CpuInfoEax = CpuInfo[0]; + *CpuInfoEbx = CpuInfo[1]; + *CpuInfoEcx = CpuInfo[2]; + *CpuInfoEdx = CpuInfo[3]; +} + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +KiSetProcessorType(VOID) +{ + ULONG64 EFlags; + INT Reg[4]; + ULONG Stepping, Type; + + /* Start by assuming no CPUID data */ + KeGetCurrentPrcb()->CpuID = 0; + + /* Save EFlags */ + EFlags = __readeflags(); + + /* Do CPUID 1 now */ + __cpuid(Reg, 1); + + /* + * Get the Stepping and Type. The stepping contains both the + * Model and the Step, while the Type contains the returned Type. + * We ignore the family. + * + * For the stepping, we convert this: zzzzzzxy into this: x0y + */ + Stepping = Reg[0] & 0xF0; + Stepping <<= 4; + Stepping += (Reg[0] & 0xFF); + Stepping &= 0xF0F; + Type = Reg[0] & 0xF00; + Type >>= 8; + + /* Save them in the PRCB */ + KeGetCurrentPrcb()->CpuID = TRUE; + KeGetCurrentPrcb()->CpuType = (UCHAR)Type; + KeGetCurrentPrcb()->CpuStep = (USHORT)Stepping; + + /* Restore EFLAGS */ + __writeeflags(EFlags); +} + +ULONG +NTAPI +KiGetCpuVendor(VOID) +{ + PKPRCB Prcb = KeGetCurrentPrcb(); + INT Vendor[5]; + + /* Get the Vendor ID and null-terminate it */ + __cpuid(Vendor, 0); + + /* Copy it to the PRCB and null-terminate it */ + *(ULONG*)&Prcb->VendorString[0] = Vendor[1]; // ebx + *(ULONG*)&Prcb->VendorString[4] = Vendor[3]; // edx + *(ULONG*)&Prcb->VendorString[8] = Vendor[2]; // ecx + *(ULONG*)&Prcb->VendorString[12] = 0; + + /* Now check the CPU Type */ + if (!strcmp((PCHAR)Prcb->VendorString, CmpIntelID)) + { + return CPU_INTEL; + } + else if (!strcmp((PCHAR)Prcb->VendorString, CmpAmdID)) + { + return CPU_AMD; + } + else if (!strcmp((PCHAR)Prcb->VendorString, CmpCyrixID)) + { + DPRINT1("Cyrix CPUs not fully supported\n"); + return 0; + } + else if (!strcmp((PCHAR)Prcb->VendorString, CmpTransmetaID)) + { + DPRINT1("Transmeta CPUs not fully supported\n"); + return 0; + } + else if (!strcmp((PCHAR)Prcb->VendorString, CmpCentaurID)) + { + DPRINT1("VIA CPUs not fully supported\n"); + return 0; + } + else if (!strcmp((PCHAR)Prcb->VendorString, CmpRiseID)) + { + DPRINT1("Rise CPUs not fully supported\n"); + return 0; + } + + /* Invalid CPU */ + return 0; +} + +ULONG +NTAPI +KiGetFeatureBits(VOID) +{ + PKPRCB Prcb = KeGetCurrentPrcb(); + ULONG Vendor; + ULONG FeatureBits = KF_WORKING_PTE; + INT Reg[4]; + ULONG CpuFeatures = 0; + + /* Get the Vendor ID */ + Vendor = KiGetCpuVendor(); + + /* Make sure we got a valid vendor ID at least. */ + if (!Vendor) return FeatureBits; + + /* Get the CPUID Info. Features are in Reg[3]. */ + __cpuid(Reg, 1); + + /* Set the initial APIC ID */ + Prcb->InitialApicId = (UCHAR)(Reg[1] >> 24); + + /* Set the current features */ + CpuFeatures = Reg[3]; + + /* Convert all CPUID Feature bits into our format */ + if (CpuFeatures & 0x00000002) FeatureBits |= KF_V86_VIS | KF_CR4; + if (CpuFeatures & 0x00000008) FeatureBits |= KF_LARGE_PAGE | KF_CR4; + if (CpuFeatures & 0x00000010) FeatureBits |= KF_RDTSC; + if (CpuFeatures & 0x00000100) FeatureBits |= KF_CMPXCHG8B; + if (CpuFeatures & 0x00000800) FeatureBits |= KF_FAST_SYSCALL; + if (CpuFeatures & 0x00001000) FeatureBits |= KF_MTRR; + if (CpuFeatures & 0x00002000) FeatureBits |= KF_GLOBAL_PAGE | KF_CR4; + if (CpuFeatures & 0x00008000) FeatureBits |= KF_CMOV; + if (CpuFeatures & 0x00010000) FeatureBits |= KF_PAT; + if (CpuFeatures & 0x00200000) FeatureBits |= KF_DTS; + if (CpuFeatures & 0x00800000) FeatureBits |= KF_MMX; + if (CpuFeatures & 0x01000000) FeatureBits |= KF_FXSR; + if (CpuFeatures & 0x02000000) FeatureBits |= KF_XMMI; + if (CpuFeatures & 0x04000000) FeatureBits |= KF_XMMI64; + +#if 0 + if (Reg[2] & 0x00000001) FeatureBits |= KF_SSE3NEW; + if (Reg[2] & 0x00000008) FeatureBits |= KF_MONITOR; + if (Reg[2] & 0x00000200) FeatureBits |= KF_SSE3SUP; + if (Reg[2] & 0x00002000) FeatureBits |= KF_CMPXCHG16B; + if (Reg[2] & 0x00080000) FeatureBits |= KF_SSE41; + if (Reg[2] & 0x00800000) FeatureBits |= KF_POPCNT; +#endif + + /* Check if the CPU has hyper-threading */ + if (CpuFeatures & 0x10000000) + { + /* Set the number of logical CPUs */ + Prcb->LogicalProcessorsPerPhysicalProcessor = (UCHAR)(Reg[1] >> 16); + if (Prcb->LogicalProcessorsPerPhysicalProcessor > 1) + { + /* We're on dual-core */ + KiSMTProcessorsPresent = TRUE; + } + } + else + { + /* We only have a single CPU */ + Prcb->LogicalProcessorsPerPhysicalProcessor = 1; + } + + /* Check extended cpuid features */ + __cpuid(Reg, 0x80000000); + if ((Reg[0] & 0xffffff00) == 0x80000000) + { + /* Check if CPUID 0x80000001 is supported */ + if (Reg[0] >= 0x80000001) + { + /* Check which extended features are available. */ + __cpuid(Reg, 0x80000001); + + /* Check if NX-bit is supported */ + if (Reg[3] & 0x00100000) FeatureBits |= KF_NX_BIT; + + /* Now handle each features for each CPU Vendor */ + switch (Vendor) + { + case CPU_AMD: + if (Reg[3] & 0x80000000) FeatureBits |= KF_3DNOW; + break; + } + } + } + + /* Return the Feature Bits */ + return FeatureBits; +} + +VOID +NTAPI +KiGetCacheInformation(VOID) +{ + PKIPCR Pcr = (PKIPCR)KeGetPcr(); + ULONG Vendor; + INT Data[4]; + ULONG CacheRequests = 0, i; + ULONG CurrentRegister; + UCHAR RegisterByte; + BOOLEAN FirstPass = TRUE; + + /* Set default L2 size */ + Pcr->SecondLevelCacheSize = 0; + + /* Get the Vendor ID and make sure we support CPUID */ + Vendor = KiGetCpuVendor(); + if (!Vendor) return; + + /* Check the Vendor ID */ + switch (Vendor) + { + /* Handle Intel case */ + case CPU_INTEL: + + /*Check if we support CPUID 2 */ + __cpuid(Data, 0); + if (Data[0] >= 2) + { + /* We need to loop for the number of times CPUID will tell us to */ + do + { + /* Do the CPUID call */ + __cpuid(Data, 2); + + /* Check if it was the first call */ + if (FirstPass) + { + /* + * The number of times to loop is the first byte. Read + * it and then destroy it so we don't get confused. + */ + CacheRequests = Data[0] & 0xFF; + Data[0] &= 0xFFFFFF00; + + /* Don't go over this again */ + FirstPass = FALSE; + } + + /* Loop all 4 registers */ + for (i = 0; i < 4; i++) + { + /* Get the current register */ + CurrentRegister = Data[i]; + + /* + * If the upper bit is set, then this register should + * be skipped. + */ + if (CurrentRegister & 0x80000000) continue; + + /* Keep looping for every byte inside this register */ + while (CurrentRegister) + { + /* Read a byte, skip a byte. */ + RegisterByte = (UCHAR)(CurrentRegister & 0xFF); + CurrentRegister >>= 8; + if (!RegisterByte) continue; + + /* + * Valid values are from 0x40 (0 bytes) to 0x49 + * (32MB), or from 0x80 to 0x89 (same size but + * 8-way associative. + */ + if (((RegisterByte > 0x40) && + (RegisterByte <= 0x49)) || + ((RegisterByte > 0x80) && + (RegisterByte <= 0x89))) + { + /* Mask out only the first nibble */ + RegisterByte &= 0x0F; + + /* Set the L2 Cache Size */ + Pcr->SecondLevelCacheSize = 0x10000 << + RegisterByte; + } + } + } + } while (--CacheRequests); + } + break; + + case CPU_AMD: + + /* Check if we support CPUID 0x80000006 */ + __cpuid(Data, 0x80000000); + if (Data[0] >= 6) + { + /* Get 2nd level cache and tlb size */ + __cpuid(Data, 0x80000006); + + /* Set the L2 Cache Size */ + Pcr->SecondLevelCacheSize = (Data[2] & 0xFFFF0000) >> 6; + } + break; + } +} + +VOID +FASTCALL +KiInitializeTss(IN PKTSS64 Tss, + IN UINT64 Stack) +{ + PKGDTENTRY64 TssEntry; + + /* Get pointer to the GDT entry */ + TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS); + + /* Initialize the GDT entry */ + KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0); + + /* Zero out the TSS */ + RtlZeroMemory(Tss, sizeof(KTSS64)); + + /* FIXME: I/O Map? */ + Tss->IoMapBase = 0x68; + + /* Setup ring 0 stack pointer */ + Tss->Rsp0 = Stack; + + /* Setup a stack for Double Fault Traps */ + Tss->Ist[1] = (ULONG64)KiDoubleFaultStack; + + /* Setup a stack for CheckAbort Traps */ + Tss->Ist[2] = (ULONG64)KiDoubleFaultStack; + + /* Setup a stack for NMI Traps */ + Tss->Ist[3] = (ULONG64)KiDoubleFaultStack; + + /* Load the task register */ + __ltr(KGDT64_SYS_TSS); +} + +VOID +NTAPI +KeFlushCurrentTb(VOID) +{ + /* Flush the TLB by resetting CR3 */ + __writecr3(__readcr3()); +} + +VOID +NTAPI +KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState) +{ + /* Restore the CR registers */ + __writecr0(ProcessorState->SpecialRegisters.Cr0); +// __writecr2(ProcessorState->SpecialRegisters.Cr2); + __writecr3(ProcessorState->SpecialRegisters.Cr3); + __writecr4(ProcessorState->SpecialRegisters.Cr4); + __writecr8(ProcessorState->SpecialRegisters.Cr8); + + /* Restore the DR registers */ + __writedr(0, ProcessorState->SpecialRegisters.KernelDr0); + __writedr(1, ProcessorState->SpecialRegisters.KernelDr1); + __writedr(2, ProcessorState->SpecialRegisters.KernelDr2); + __writedr(3, ProcessorState->SpecialRegisters.KernelDr3); + __writedr(6, ProcessorState->SpecialRegisters.KernelDr6); + __writedr(7, ProcessorState->SpecialRegisters.KernelDr7); + + /* Restore GDT, IDT, LDT and TSS */ + __lgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit); +// __lldt(&ProcessorState->SpecialRegisters.Ldtr); +// __ltr(&ProcessorState->SpecialRegisters.Tr); + __lidt(&ProcessorState->SpecialRegisters.Idtr.Limit); + +// __ldmxcsr(&ProcessorState->SpecialRegisters.MxCsr); // FIXME +// ProcessorState->SpecialRegisters.DebugControl +// ProcessorState->SpecialRegisters.LastBranchToRip +// ProcessorState->SpecialRegisters.LastBranchFromRip +// ProcessorState->SpecialRegisters.LastExceptionToRip +// ProcessorState->SpecialRegisters.LastExceptionFromRip + + /* Restore MSRs */ + __writemsr(X86_MSR_GSBASE, ProcessorState->SpecialRegisters.MsrGsBase); + __writemsr(X86_MSR_KERNEL_GSBASE, ProcessorState->SpecialRegisters.MsrGsSwap); + __writemsr(X86_MSR_STAR, ProcessorState->SpecialRegisters.MsrStar); + __writemsr(X86_MSR_LSTAR, ProcessorState->SpecialRegisters.MsrLStar); + __writemsr(X86_MSR_CSTAR, ProcessorState->SpecialRegisters.MsrCStar); + __writemsr(X86_MSR_SFMASK, ProcessorState->SpecialRegisters.MsrSyscallMask); + +} + +VOID +NTAPI +KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState) +{ + /* Save the CR registers */ + ProcessorState->SpecialRegisters.Cr0 = __readcr0(); + ProcessorState->SpecialRegisters.Cr2 = __readcr2(); + ProcessorState->SpecialRegisters.Cr3 = __readcr3(); + ProcessorState->SpecialRegisters.Cr4 = __readcr4(); + ProcessorState->SpecialRegisters.Cr8 = __readcr8(); + + /* Save the DR registers */ + ProcessorState->SpecialRegisters.KernelDr0 = __readdr(0); + ProcessorState->SpecialRegisters.KernelDr1 = __readdr(1); + ProcessorState->SpecialRegisters.KernelDr2 = __readdr(2); + ProcessorState->SpecialRegisters.KernelDr3 = __readdr(3); + ProcessorState->SpecialRegisters.KernelDr6 = __readdr(6); + ProcessorState->SpecialRegisters.KernelDr7 = __readdr(7); + + /* Save GDT, IDT, LDT and TSS */ + __sgdt(&ProcessorState->SpecialRegisters.Gdtr.Limit); + __sldt(&ProcessorState->SpecialRegisters.Ldtr); + __str(&ProcessorState->SpecialRegisters.Tr); + __sidt(&ProcessorState->SpecialRegisters.Idtr.Limit); + +// __stmxcsr(&ProcessorState->SpecialRegisters.MxCsr); +// ProcessorState->SpecialRegisters.DebugControl = +// ProcessorState->SpecialRegisters.LastBranchToRip = +// ProcessorState->SpecialRegisters.LastBranchFromRip = +// ProcessorState->SpecialRegisters.LastExceptionToRip = +// ProcessorState->SpecialRegisters.LastExceptionFromRip = + + /* Save MSRs */ + ProcessorState->SpecialRegisters.MsrGsBase = __readmsr(X86_MSR_GSBASE); + ProcessorState->SpecialRegisters.MsrGsSwap = __readmsr(X86_MSR_KERNEL_GSBASE); + ProcessorState->SpecialRegisters.MsrStar = __readmsr(X86_MSR_STAR); + ProcessorState->SpecialRegisters.MsrLStar = __readmsr(X86_MSR_LSTAR); + ProcessorState->SpecialRegisters.MsrCStar = __readmsr(X86_MSR_CSTAR); + ProcessorState->SpecialRegisters.MsrSyscallMask = __readmsr(X86_MSR_SFMASK); +} + +VOID +NTAPI +KeFlushEntireTb(IN BOOLEAN Invalid, + IN BOOLEAN AllProcessors) +{ + KIRQL OldIrql; + + // FIXME: halfplemented + /* Raise the IRQL for the TB Flush */ + OldIrql = KeRaiseIrqlToSynchLevel(); + + /* Flush the TB for the Current CPU, and update the flush stamp */ + KeFlushCurrentTb(); + + /* Update the flush stamp and return to original IRQL */ + InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1); + KeLowerIrql(OldIrql); + +} + +KAFFINITY +NTAPI +KeQueryActiveProcessors(VOID) +{ + PAGED_CODE(); + + /* Simply return the number of active processors */ + return KeActiveProcessors; +} + +NTSTATUS +NTAPI +KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +NTAPI +KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +BOOLEAN +NTAPI +KeInvalidateAllCaches(VOID) +{ + /* Invalidate all caches */ + __wbinvd(); + return TRUE; +} + +/* + * @implemented + */ +ULONG +NTAPI +KeGetRecommendedSharedDataAlignment(VOID) +{ + /* Return the global variable */ + return KeLargestCacheLine; +} + +/* + * @implemented + */ +VOID +__cdecl +KeSaveStateForHibernate(IN PKPROCESSOR_STATE State) +{ + /* Capture the context */ + RtlCaptureContext(&State->ContextFrame); + + /* Capture the control state */ + KiSaveProcessorControlState(State); +} + +/* + * @implemented + */ +VOID +NTAPI +KeSetDmaIoCoherency(IN ULONG Coherency) +{ + /* Save the coherency globally */ + KiDmaIoCoherency = Coherency; +} diff --git a/reactos/ntoskrnl/ke/amd64/ctxswitch.S b/reactos/ntoskrnl/ke/amd64/ctxswitch.S new file mode 100644 index 00000000000..61ce1473e53 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/ctxswitch.S @@ -0,0 +1,199 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ke/amd64/ctxswitch.S + * PURPOSE: Thread Context Switching + * + * PROGRAMMER: Timo kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#include + +/* FUNCTIONS ****************************************************************/ + +.code64 + +/*++ + * KiThreadStartup + * + * The KiThreadStartup routine is the beginning of any thread. + * + * Params: + * SystemRoutine - Pointer to the System Startup Routine. Either + * PspUserThreadStartup or PspSystemThreadStartup + * + * StartRoutine - For Kernel Threads only, specifies the starting execution + * point of the new thread. + * + * StartContext - For Kernel Threads only, specifies a pointer to variable + * context data to be sent to the StartRoutine above. + * + * UserThread - Indicates whether or not this is a user thread. This tells + * us if the thread has a context or not. + * + * TrapFrame - Pointer to the KTHREAD to which the caller wishes to + * switch from. + * + * Returns: + * Should never return for a system thread. Returns through the System Call + * Exit Dispatcher for a user thread. + * + * Remarks: + * If a return from a system thread is detected, a bug check will occur. + * + *--*/ +PUBLIC KiThreadStartup +KiThreadStartup: + + /* + * Clear all the non-volatile registers, so the thread won't be tempted to + * expect any static data (like some badly coded usermode/win9x apps do) + */ + xor rbx, rbx + xor rsi, rsi + xor rdi, rdi + xor rbp, rbp + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 + + /* It's now safe to go to APC */ + mov rax, APC_LEVEL + mov cr8, rax + + /* + * Call the System Routine which is right on our stack now. + * After we pop the pointer, the Start Routine/Context is on the + * stack, we pop it as parameters to the System Routine into rcx + */ + pop rax + pop rcx + call rax + + /* The thread returned... was it a user-thread? */ + pop rcx + or rcx, rcx + jz BadThread + + /* Yes it was, set our trapframe for the System Call Exit Dispatcher */ + mov ebp, esp + + /* Exit back to user-mode */ +// jmp _KiServiceExit2 +UNIMPLEMENTED KiThreadStartup_KiServiceExit2 + +BadThread: + + /* A system thread returned...this is very bad! */ + int 3 + + +/*++ + * KiSwapContextInternal + * + * The KiSwapContextInternal routine switches context to another thread. + * + * Params: + * ESI - Pointer to the KTHREAD to which the caller wishes to + * switch to. + * EDI - Pointer to the KTHREAD to which the caller wishes to + * switch from. + * + * Returns: + * None. + * + * Remarks: + * Absolutely all registers except ESP can be trampled here for maximum code flexibility. + * + *--*/ +PUBLIC KiSwapContextInternal +KiSwapContextInternal: + UNIMPLEMENTED KiSwapContextInternal + ret + + +/** + * KiSwapContext + * + * \brief + * The KiSwapContext routine switches context to another thread. + * + * BOOLEAN + * KiSwapContext(PKTHREAD CurrentThread, PKTHREAD TargetThread); + * + * \param CurrentThread + * Pointer to the KTHREAD of the current thread. + * + * \param TargetThread + * Pointer to the KTHREAD to which the caller wishes to switch to. + * + * \returns + * The WaitStatus of the Target Thread. + * + * \remarks + * This is a wrapper around KiSwapContextInternal which will save all the + * non-volatile registers so that the Internal function can use all of + * them. It will also save the old current thread and set the new one. + * + * The calling thread does not return after KiSwapContextInternal until + * another thread switches to IT. + * + *--*/ +PUBLIC KiSwapContext +KiSwapContext: + + /* Save 10 registers */ + sub rsp, 10 * 8 + + /* Save all the non-volatile ones */ + mov [rsp+72], r15 + mov [rsp+64], r14 + mov [rsp+56], r13 + mov [rsp+48], r12 + mov [rsp+40], r11 + mov [rsp+32], r10 + + mov [rsp+24], rbx + mov [rsp+16], rsi + mov [rsp+8], rdi + mov [rsp+0], rbp + + /* Get the PCR */ + mov rbx, gs:[KPCR_SELF] + + /* Get the current thread */ + mov rdi, rcx + + /* Get the New Thread */ + mov rsi, rdx + + /* Get the wait IRQL */ + movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL] + + /* Do the swap with the registers correctly setup */ + call KiSwapContextInternal + + /* Restore the registers */ + mov rbp, [rsp+0] + mov rdi, [rsp+8] + mov rsi, [rsp+16] + mov rbx, [rsp+24] + + mov r10, [rsp+32] + mov r11, [rsp+40] + mov r12, [rsp+48] + mov r13, [rsp+56] + mov r14, [rsp+64] + mov r15, [rsp+72] + + /* Clean stack */ + add esp, 10 * 8 + ret + +END diff --git a/reactos/ntoskrnl/ke/amd64/except.c b/reactos/ntoskrnl/ke/amd64/except.c new file mode 100644 index 00000000000..97845595b43 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/except.c @@ -0,0 +1,299 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ke/amd64/except.c + * PURPOSE: Exception Dispatching for amd64 + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + * Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +extern ULONG64 InterruptDispatchTable[256]; + +/* GLOBALS *******************************************************************/ + +KIDT_INIT KiInterruptInitTable[] = +{ + /* Id, Dpl, IST, ServiceRoutine */ + {0x00, 0x00, 0x00, KiDivideErrorFault}, + {0x01, 0x00, 0x00, KiDebugTrapOrFault}, + {0x02, 0x00, 0x03, KiNmiInterrupt}, + {0x03, 0x03, 0x00, KiBreakpointTrap}, + {0x04, 0x03, 0x00, KiOverflowTrap}, + {0x05, 0x00, 0x00, KiBoundFault}, + {0x06, 0x00, 0x00, KiInvalidOpcodeFault}, + {0x07, 0x00, 0x00, KiNpxNotAvailableFault}, + {0x08, 0x00, 0x01, KiDoubleFaultAbort}, + {0x09, 0x00, 0x00, KiNpxSegmentOverrunAbort}, + {0x0A, 0x00, 0x00, KiInvalidTssFault}, + {0x0B, 0x00, 0x00, KiSegmentNotPresentFault}, + {0x0C, 0x00, 0x00, KiStackFault}, + {0x0D, 0x00, 0x00, KiGeneralProtectionFault}, + {0x0E, 0x00, 0x00, KiPageFault}, + {0x10, 0x00, 0x00, KiFloatingErrorFault}, + {0x11, 0x00, 0x00, KiAlignmentFault}, + {0x12, 0x00, 0x02, KiMcheckAbort}, + {0x13, 0x00, 0x00, KiXmmException}, + {0x1F, 0x00, 0x00, KiApcInterrupt}, + {0x2C, 0x03, 0x00, KiRaiseAssertion}, + {0x2D, 0x03, 0x00, KiDebugServiceTrap}, + {0x2F, 0x00, 0x00, KiDpcInterrupt}, + {0xE1, 0x00, 0x00, KiIpiInterrupt}, + {0, 0, 0, 0} +}; + +KIDTENTRY64 KiIdt[256]; +KDESCRIPTOR KiIdtDescriptor = {{0}, sizeof(KiIdt) - 1, KiIdt}; + + +/* FUNCTIONS *****************************************************************/ + +VOID +INIT_FUNCTION +NTAPI +KeInitExceptions(VOID) +{ + int i, j; + + /* Initialize the Idt */ + for (j = i = 0; i < 256; i++) + { + ULONG64 Offset; + + if (KiInterruptInitTable[j].InterruptId == i) + { + Offset = (ULONG64)KiInterruptInitTable[j].ServiceRoutine; + KiIdt[i].Dpl = KiInterruptInitTable[j].Dpl; + KiIdt[i].IstIndex = KiInterruptInitTable[j].IstIndex; + j++; + } + else + { + Offset = (ULONG64)&InterruptDispatchTable[i]; + KiIdt[i].Dpl = 0; + KiIdt[i].IstIndex = 0; + } + KiIdt[i].OffsetLow = Offset & 0xffff; + KiIdt[i].Selector = KGDT64_R0_CODE; + KiIdt[i].Type = 0x0e; + KiIdt[i].Reserved0 = 0; + KiIdt[i].Present = 1; + KiIdt[i].OffsetMiddle = (Offset >> 16) & 0xffff; + KiIdt[i].OffsetHigh = (Offset >> 32); + KiIdt[i].Reserved1 = 0; + } + + KeGetPcr()->IdtBase = KiIdt; + __lidt(&KiIdtDescriptor.Limit); +} + +VOID +NTAPI +KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame, + IN KPROCESSOR_MODE PreviousMode, + IN BOOLEAN FirstChance) +{ + CONTEXT Context; + +// FrLdrDbgPrint("KiDispatchException(%p, %p, %p, %d, %d)\n", +// ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance); + + /* Increase number of Exception Dispatches */ + KeGetCurrentPrcb()->KeExceptionDispatchCount++; + + /* Set the context flags */ + Context.ContextFlags = CONTEXT_ALL; + + /* Get a Context */ + KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); + + /* Look at our exception code */ + switch (ExceptionRecord->ExceptionCode) + { + /* Breakpoint */ + case STATUS_BREAKPOINT: + + /* Decrement RIP by one */ + Context.Rip--; + break; + + /* Internal exception */ + case KI_EXCEPTION_ACCESS_VIOLATION: + + /* Set correct code */ + ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; + if (PreviousMode == UserMode) + { + /* FIXME: Handle no execute */ + } + break; + } + + /* Handle kernel-mode first, it's simpler */ + if (PreviousMode == KernelMode) + { + /* Check if this is a first-chance exception */ + if (FirstChance == TRUE) + { + /* Break into the debugger for the first time */ + if (KiDebugRoutine(TrapFrame, + ExceptionFrame, + ExceptionRecord, + &Context, + PreviousMode, + FALSE)) + { + /* Exception was handled */ + goto Handled; + } + + /* If the Debugger couldn't handle it, dispatch the exception */ + if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled; + } + + /* This is a second-chance exception, only for the debugger */ + if (KiDebugRoutine(TrapFrame, + ExceptionFrame, + ExceptionRecord, + &Context, + PreviousMode, + TRUE)) + { + /* Exception was handled */ + goto Handled; + } + + /* Third strike; you're out */ + KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, + ExceptionRecord->ExceptionCode, + (ULONG_PTR)ExceptionRecord->ExceptionAddress, + (ULONG_PTR)TrapFrame, + 0); + } + else + { + /* FIXME: user-mode exception handling unimplemented */ + ASSERT(FALSE); + } + +Handled: + /* Convert the context back into Trap/Exception Frames */ + KeContextToTrapFrame(&Context, + ExceptionFrame, + TrapFrame, + Context.ContextFlags, + PreviousMode); + return; +} + +NTSTATUS +NTAPI +KeRaiseUserException(IN NTSTATUS ExceptionCode) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + + +VOID +DECLSPEC_NORETURN +KiSystemFatalException(IN ULONG ExceptionCode, + IN PKTRAP_FRAME TrapFrame) +{ + /* Bugcheck the system */ + KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP, + ExceptionCode, + 0, + 0, + 0, + TrapFrame); +} + +NTSTATUS +NTAPI +KiNpxNotAvailableFaultHandler( + IN PKTRAP_FRAME TrapFrame) +{ + UNIMPLEMENTED; + KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); + return -1; +} + + +NTSTATUS +NTAPI +KiGeneralProtectionFaultHandler( + IN PKTRAP_FRAME TrapFrame) +{ + PUCHAR Instructions; + + /* Check for user-mode GPF */ + if (TrapFrame->SegCs & 3) + { + UNIMPLEMENTED; + ASSERT(FALSE); + } + + /* Check for lazy segment load */ + if (TrapFrame->SegDs != (KGDT64_R3_DATA | RPL_MASK)) + { + /* Fix it */ + TrapFrame->SegDs = (KGDT64_R3_DATA | RPL_MASK); + return STATUS_SUCCESS; + } + else if (TrapFrame->SegEs != (KGDT64_R3_DATA | RPL_MASK)) + { + /* Fix it */ + TrapFrame->SegEs = (KGDT64_R3_DATA | RPL_MASK); + return STATUS_SUCCESS; + } + + /* Check for nested exception */ + if ((TrapFrame->Rip >= (ULONG64)KiGeneralProtectionFaultHandler) && + (TrapFrame->Rip < (ULONG64)KiGeneralProtectionFaultHandler)) + { + /* Not implemented */ + UNIMPLEMENTED; + ASSERT(FALSE); + } + + /* Get Instruction Pointer */ + Instructions = (PUCHAR)TrapFrame->Rip; + + /* Check for IRET */ + if (Instructions[0] == 0x48 && Instructions[1] == 0xCF) + { + /* Not implemented */ + UNIMPLEMENTED; + ASSERT(FALSE); + } + + /* Check for RDMSR/WRMSR */ + if ((Instructions[0] == 0xF) && // 2-byte opcode + (((Instructions[1] >> 8) == 0x30) || // RDMSR + ((Instructions[2] >> 8) == 0x32))) // WRMSR + { + /* Unknown CPU MSR, so raise an access violation */ + return STATUS_ACCESS_VIOLATION; + } + + ASSERT(FALSE); + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +NTAPI +KiXmmExceptionHandler( + IN PKTRAP_FRAME TrapFrame) +{ + UNIMPLEMENTED; + KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); + return -1; +} diff --git a/reactos/ntoskrnl/ke/amd64/interrupt.c b/reactos/ntoskrnl/ke/amd64/interrupt.c new file mode 100644 index 00000000000..171ebda7716 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/interrupt.c @@ -0,0 +1,62 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ke/i386/irq.c + * PURPOSE: Manages the Kernel's IRQ support for external drivers, + * for the purpopses of connecting, disconnecting and setting + * up ISRs for drivers. The backend behind the Io* Interrupt + * routines. + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@web.de) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + + + +BOOLEAN +NTAPI +KeDisableInterrupts(VOID) +{ + ULONG64 Flags; + + /* Get the flags */ + Flags = __readeflags(); + + /* Disable interrupts */ + _disable(); + + return !!(Flags & EFLAGS_INTERRUPT_MASK); +} + + +BOOLEAN +NTAPI +KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) +{ + UNIMPLEMENTED; + return FALSE; +} + +VOID +NTAPI +KeInitializeInterrupt(IN PKINTERRUPT Interrupt, + IN PKSERVICE_ROUTINE ServiceRoutine, + IN PVOID ServiceContext, + IN PKSPIN_LOCK SpinLock, + IN ULONG Vector, + IN KIRQL Irql, + IN KIRQL SynchronizeIrql, + IN KINTERRUPT_MODE InterruptMode, + IN BOOLEAN ShareVector, + IN CHAR ProcessorNumber, + IN BOOLEAN FloatingSave) +{ + UNIMPLEMENTED; +} + diff --git a/reactos/ntoskrnl/ke/amd64/irql.c b/reactos/ntoskrnl/ke/amd64/irql.c new file mode 100644 index 00000000000..53dcd3890b6 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/irql.c @@ -0,0 +1,45 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * PURPOSE: Routines for IRQL support + * PROGRAMMERS: Timo Kreuzer + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ****************************************************************/ + +NTKERNELAPI +KIRQL +KxGetCurrentIrql(VOID) +{ + return KeGetCurrentIrql(); +} + +NTKERNELAPI +VOID +KxLowerIrql(IN KIRQL NewIrql) +{ + KeLowerIrql(NewIrql); +} + +NTKERNELAPI +KIRQL +KxRaiseIrql(IN KIRQL NewIrql) +{ + return KfRaiseIrql(NewIrql); +} + +NTKERNELAPI +KIRQL +KxRaiseIrqlToDpcLevel(VOID) +{ + return KeRaiseIrqlToDpcLevel(); +} + + +/* EOF */ diff --git a/reactos/ntoskrnl/ke/amd64/kiinit.c b/reactos/ntoskrnl/ke/amd64/kiinit.c new file mode 100644 index 00000000000..d2704638f50 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/kiinit.c @@ -0,0 +1,502 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ke/i386/kiinit.c + * PURPOSE: Kernel Initialization for x86 CPUs + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +#define REQUIRED_FEATURE_BITS (KF_RDTSC|KF_CR4|KF_CMPXCHG8B|KF_XMMI|KF_XMMI64| \ + KF_NX_BIT) + +/* GLOBALS *******************************************************************/ + +/* Function pointer for early debug prints */ +ULONG (*FrLdrDbgPrint)(const char *Format, ...); + +/* Spinlocks used only on X86 */ +KSPIN_LOCK KiFreezeExecutionLock; + +/* BIOS Memory Map. Not NTLDR-compliant yet */ +extern ULONG KeMemoryMapRangeCount; +extern ADDRESS_RANGE KeMemoryMap[64]; + +KIPCR KiInitialPcr; + +/* Boot and double-fault/NMI/DPC stack */ +UCHAR DECLSPEC_ALIGN(16) P0BootStackData[KERNEL_STACK_SIZE] = {0}; +UCHAR DECLSPEC_ALIGN(16) KiDoubleFaultStackData[KERNEL_STACK_SIZE] = {0}; +ULONG_PTR P0BootStack = (ULONG_PTR)&P0BootStackData[KERNEL_STACK_SIZE]; +ULONG_PTR KiDoubleFaultStack = (ULONG_PTR)&KiDoubleFaultStackData[KERNEL_STACK_SIZE]; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +KiInitMachineDependent(VOID) +{ + /* Check for large page support */ + if (KeFeatureBits & KF_LARGE_PAGE) + { + /* FIXME: Support this */ + DPRINT1("Large Page support detected but not yet taken advantage of!\n"); + } + + /* Check for global page support */ + if (KeFeatureBits & KF_GLOBAL_PAGE) + { + /* FIXME: Support this */ + DPRINT1("Global Page support detected but not yet taken advantage of!\n"); + } + + /* Check if we have MTRR */ + if (KeFeatureBits & KF_MTRR) + { + /* FIXME: Support this */ + DPRINT1("MTRR support detected but not yet taken advantage of!\n"); + } + + /* Check for PAT and/or MTRR support */ + if (KeFeatureBits & KF_PAT) + { + /* FIXME: Support this */ + DPRINT1("PAT support detected but not yet taken advantage of!\n"); + } + + +} + +VOID +NTAPI +KiInitializePcr(IN PKIPCR Pcr, + IN ULONG ProcessorNumber, + IN PKTHREAD IdleThread, + IN PVOID DpcStack) +{ + KDESCRIPTOR GdtDescriptor = {{0},0,0}, IdtDescriptor = {{0},0,0}; + PKGDTENTRY64 TssEntry; + USHORT Tr = 0; + + /* Zero out the PCR */ + RtlZeroMemory(Pcr, PAGE_SIZE); + + /* Set pointers to ourselves */ + Pcr->Self = (PKPCR)Pcr; + Pcr->CurrentPrcb = &Pcr->Prcb; + + /* Set the PCR Version */ + Pcr->MajorVersion = PCR_MAJOR_VERSION; + Pcr->MinorVersion = PCR_MINOR_VERSION; + + /* Set the PRCB Version */ + Pcr->Prcb.MajorVersion = 1; + Pcr->Prcb.MinorVersion = 1; + + /* Set the Build Type */ + Pcr->Prcb.BuildType = 0; +#ifndef CONFIG_SMP + Pcr->Prcb.BuildType |= PRCB_BUILD_UNIPROCESSOR; +#endif +#ifdef DBG + Pcr->Prcb.BuildType |= PRCB_BUILD_DEBUG; +#endif + + /* Set the Processor Number and current Processor Mask */ + Pcr->Prcb.Number = (UCHAR)ProcessorNumber; + Pcr->Prcb.SetMember = 1 << ProcessorNumber; + + /* Get GDT and IDT descriptors */ + __sgdt(&GdtDescriptor.Limit); + __sidt(&IdtDescriptor.Limit); + Pcr->GdtBase = (PVOID)GdtDescriptor.Base; + Pcr->IdtBase = (PKIDTENTRY)IdtDescriptor.Base; + + /* Get TSS Selector */ + __str(&Tr); + ASSERT(Tr == KGDT64_SYS_TSS); + + /* Get TSS Entry */ + TssEntry = KiGetGdtEntry(Pcr->GdtBase, Tr); + + /* Get the KTSS itself */ + Pcr->TssBase = KiGetGdtDescriptorBase(TssEntry); + + Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; // FIXME + + /* Set DPC Stack */ + Pcr->Prcb.DpcStack = DpcStack; + + /* Setup the processor set */ + Pcr->Prcb.MultiThreadProcessorSet = Pcr->Prcb.SetMember; + + /* Clear DR6/7 to cleanup bootloader debugging */ + Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr6 = 0; + Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr7 = 0; + + /* Set the Current Thread */ + Pcr->Prcb.CurrentThread = IdleThread; + + /* Start us out at PASSIVE_LEVEL */ + Pcr->Irql = PASSIVE_LEVEL; + KeSetCurrentIrql(PASSIVE_LEVEL); + +} + +VOID +NTAPI +KiInitializeCpuFeatures(ULONG Cpu) +{ + ULONG FeatureBits; + + /* Get the processor features for this CPU */ + FeatureBits = KiGetFeatureBits(); + + /* Check if we support all needed features */ + if ((FeatureBits & REQUIRED_FEATURE_BITS) != REQUIRED_FEATURE_BITS) + { + /* If not, bugcheck system */ + FrLdrDbgPrint("CPU doesn't have needed features! Has: 0x%x, required: 0x%x\n", + FeatureBits, REQUIRED_FEATURE_BITS); + KeBugCheck(0); + } + + /* Set DEP to always on */ + SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON; + FeatureBits |= KF_NX_ENABLED; + + /* Save feature bits */ + KeGetCurrentPrcb()->FeatureBits = FeatureBits; + + /* Enable fx save restore support */ + __writecr4(__readcr4() | CR4_FXSR); + + /* Enable XMMI exceptions */ + __writecr4(__readcr4() | CR4_XMMEXCPT); + + /* Enable Write-Protection */ + __writecr0(__readcr0() | CR0_WP); + + /* Disable fpu monitoring */ + __writecr0(__readcr0() & ~CR0_MP); + + /* Disable x87 fpu exceptions */ + __writecr0(__readcr0() & ~CR0_NE); + +} + +VOID +NTAPI +KiInitializeKernel(IN PKPROCESS InitProcess, + IN PKTHREAD InitThread, + IN PVOID IdleStack, + IN PKPRCB Prcb, + IN CCHAR Number, + IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + ULONG PageDirectory[2]; + PVOID DpcStack; + + /* Detect and set the CPU Type */ + KiSetProcessorType(); + + /* Initialize the Power Management Support for this PRCB */ +// PoInitializePrcb(Prcb); + + /* Save CPU state */ + KiSaveProcessorControlState(&Prcb->ProcessorState); + + /* Get cache line information for this CPU */ + KiGetCacheInformation(); + + /* Initialize spinlocks and DPC data */ + KiInitSpinLocks(Prcb, Number); + + /* Check if this is the Boot CPU */ + if (Number == 0) + { + /* Set Node Data */ + KeNodeBlock[0] = &KiNode0; + Prcb->ParentNode = KeNodeBlock[0]; + KeNodeBlock[0]->ProcessorMask = Prcb->SetMember; + + /* Set boot-level flags */ + KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; + KeProcessorLevel = (USHORT)Prcb->CpuType; + if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep; + + /* Set the current MP Master KPRCB to the Boot PRCB */ + Prcb->MultiThreadSetMaster = Prcb; + + /* Lower to APC_LEVEL */ + KeLowerIrql(APC_LEVEL); + + /* Initialize some spinlocks */ + KeInitializeSpinLock(&KiFreezeExecutionLock); + + /* Initialize portable parts of the OS */ + KiInitSystem(); + + /* Initialize the Idle Process and the Process Listhead */ + InitializeListHead(&KiProcessListHead); + PageDirectory[0] = 0; + PageDirectory[1] = 0; + KeInitializeProcess(InitProcess, + 0, + 0xFFFFFFFF, + PageDirectory, + FALSE); + InitProcess->QuantumReset = MAXCHAR; + } + else + { + /* FIXME */ + DPRINT1("SMP Boot support not yet present\n"); + } + + /* HACK for MmUpdatePageDir */ + ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess; + + /* Setup the Idle Thread */ + KeInitializeThread(InitProcess, + InitThread, + NULL, + NULL, + NULL, + NULL, + NULL, + IdleStack); + + InitThread->NextProcessor = Number; + InitThread->Priority = HIGH_PRIORITY; + InitThread->State = Running; + InitThread->Affinity = 1 << Number; + InitThread->WaitIrql = DISPATCH_LEVEL; + InitProcess->ActiveProcessors = 1 << Number; + + /* Set basic CPU Features that user mode can read */ + SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = + (KeFeatureBits & KF_MMX) ? TRUE: FALSE; + SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] = + (KeFeatureBits & KF_CMPXCHG8B) ? TRUE: FALSE; + SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] = + ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI)) ? TRUE: FALSE; + SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] = + ((KeFeatureBits & KF_FXSR) && (KeFeatureBits & KF_XMMI64)) ? TRUE: FALSE; + SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] = + (KeFeatureBits & KF_3DNOW) ? TRUE: FALSE; + SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] = + (KeFeatureBits & KF_RDTSC) ? TRUE: FALSE; + + /* Set up the thread-related fields in the PRCB */ + Prcb->CurrentThread = InitThread; + Prcb->NextThread = NULL; + Prcb->IdleThread = InitThread; + + /* Initialize the Kernel Executive */ + ExpInitializeExecutive(Number, LoaderBlock); + + /* Only do this on the boot CPU */ + if (Number == 0) + { + /* Calculate the time reciprocal */ + KiTimeIncrementReciprocal = + KiComputeReciprocal(KeMaximumIncrement, + &KiTimeIncrementShiftCount); + + /* Update DPC Values in case they got updated by the executive */ + Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; + Prcb->MinimumDpcRate = KiMinimumDpcRate; + Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; + + /* Allocate the DPC Stack */ + DpcStack = MmCreateKernelStack(FALSE, 0); + if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0); + Prcb->DpcStack = DpcStack; + + /* Allocate the IOPM save area. */ +// Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool, +// PAGE_SIZE * 2, +// TAG('K', 'e', ' ', ' ')); +// if (!Ki386IopmSaveArea) +// { +// /* Bugcheck. We need this for V86/VDM support. */ +// KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0); +// } + } + + /* Raise to Dispatch */ + KfRaiseIrql(DISPATCH_LEVEL); + + /* Set the Idle Priority to 0. This will jump into Phase 1 */ + KeSetPriorityThread(InitThread, 0); + + /* If there's no thread scheduled, put this CPU in the Idle summary */ + KiAcquirePrcbLock(Prcb); + if (!Prcb->NextThread) KiIdleSummary |= 1 << Number; + KiReleasePrcbLock(Prcb); + + /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */ + KfRaiseIrql(HIGH_LEVEL); + LoaderBlock->Prcb = 0; +} + +VOID +NTAPI +KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + ULONG Cpu; + PKTHREAD InitialThread; + ULONG64 InitialStack; + PKIPCR Pcr; + + /* HACK */ + FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea; + FrLdrDbgPrint("Hello from KiSystemStartup!!!\n"); + + /* HACK, because freeldr maps page 0 */ + MiAddressToPte((PVOID)0)->u.Hard.Valid = 0; + + /* Save the loader block */ + KeLoaderBlock = LoaderBlock; + + /* Get the current CPU number */ + Cpu = KeNumberProcessors++; // FIXME + + /* LoaderBlock initialization for Cpu 0 */ + if (Cpu == 0) + { + /* Set the initial stack, idle thread and process */ + LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; + LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; + LoaderBlock->Process = (ULONG_PTR)&KiInitialProcess.Pcb; + LoaderBlock->Prcb = (ULONG_PTR)&KiInitialPcr.Prcb; + } + + /* Get Pcr from loader block */ + Pcr = CONTAINING_RECORD(LoaderBlock->Prcb, KIPCR, Prcb); + + /* Set the PRCB for this Processor */ + KiProcessorBlock[Cpu] = &Pcr->Prcb; + + /* Set GS base */ + __writemsr(X86_MSR_GSBASE, (ULONG64)Pcr); + __writemsr(X86_MSR_KERNEL_GSBASE, (ULONG64)Pcr); + + /* LDT is unused */ + __lldt(0); + + /* Align stack to 16 bytes */ + LoaderBlock->KernelStack &= ~(16 - 1); + + /* Save the initial thread and stack */ + InitialStack = LoaderBlock->KernelStack; // Checkme + InitialThread = (PKTHREAD)LoaderBlock->Thread; + + /* Clean the APC List Head */ + InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]); + + /* Set us as the current process */ + InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process; + + /* Initialize the PCR */ + KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack); + + /* Initialize the CPU features */ + KiInitializeCpuFeatures(Cpu); + + /* Initial setup for the boot CPU */ + if (Cpu == 0) + { + /* Setup the TSS descriptors and entries */ + KiInitializeTss(Pcr->TssBase, InitialStack); + + /* Setup the IDT */ + KeInitExceptions(); + + /* HACK: misuse this function to pass a function pointer to kdcom */ + KdDebuggerInitialize1((PVOID)FrLdrDbgPrint); + + /* Initialize debugging system */ + KdInitSystem(0, KeLoaderBlock); + + /* Check for break-in */ + if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); + + /* Hack! Wait for the debugger! */ +#ifdef _WINKD_ + while (!KdPollBreakIn()); + DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); +#endif + } + + DPRINT("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n", + Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase); + + /* Acquire lock */ + while (InterlockedBitTestAndSet64((PLONG64)&KiFreezeExecutionLock, 0)) + { + /* Loop until lock is free */ + while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1); + } + + /* Initialize the Processor with HAL */ + HalInitializeProcessor(Cpu, KeLoaderBlock); + + /* Set processor as active */ + KeActiveProcessors |= 1 << Cpu; + + /* Release lock */ + InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0); + + /* Raise to HIGH_LEVEL */ + KfRaiseIrql(HIGH_LEVEL); + + /* Switch to new kernel stack and start kernel bootstrapping */ + KiSetupStackAndInitializeKernel(&KiInitialProcess.Pcb, + InitialThread, + (PVOID)InitialStack, + &Pcr->Prcb, + (CCHAR)Cpu, + KeLoaderBlock); +} + + +VOID +NTAPI +KiInitializeKernelAndGotoIdleLoop(IN PKPROCESS InitProcess, + IN PKTHREAD InitThread, + IN PVOID IdleStack, + IN PKPRCB Prcb, + IN CCHAR Number, + IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ +// DbgBreakPointWithStatus(0); + + /* Initialize kernel */ + KiInitializeKernel(InitProcess, + InitThread, + IdleStack, + Prcb, + Number, + KeLoaderBlock); + + /* Set the priority of this thread to 0 */ + InitThread->Priority = 0; + + /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */ + _enable(); + KeLowerIrql(DISPATCH_LEVEL); + + /* Set the right wait IRQL */ + InitThread->WaitIrql = DISPATCH_LEVEL; + + /* Jump into the idle loop */ + KiIdleLoop(); +} diff --git a/reactos/ntoskrnl/ke/amd64/spinlock.c b/reactos/ntoskrnl/ke/amd64/spinlock.c new file mode 100644 index 00000000000..9c485fd8d43 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/spinlock.c @@ -0,0 +1,196 @@ +/* + * PROJECT: ReactOS HAL + * LICENSE: GPL - See COPYING in the top level directory + * FILE: hal/halx86/up/spinlock.c + * PURPOSE: Spinlock and Queued Spinlock Support + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +#undef KeAcquireSpinLock +#undef KeReleaseSpinLock + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +KIRQL +KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock) +{ +#ifndef CONFIG_SMP + KIRQL OldIrql; + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + return OldIrql; +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +KIRQL +NTAPI +KeAcquireSpinLockRaiseToDpc(PKSPIN_LOCK SpinLock) +{ +#ifndef CONFIG_SMP + KIRQL OldIrql; + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + return OldIrql; +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +VOID +NTAPI +KeReleaseSpinLock(PKSPIN_LOCK SpinLock, + KIRQL OldIrql) +{ +#ifndef CONFIG_SMP + /* Simply lower IRQL back */ + KeLowerIrql(OldIrql); +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +KIRQL +KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber) +{ +#ifndef CONFIG_SMP + KIRQL OldIrql; + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + return OldIrql; +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +KIRQL +KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber) +{ +#ifndef CONFIG_SMP + KIRQL OldIrql; + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + return OldIrql; +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +VOID +KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockHandle) +{ +#ifndef CONFIG_SMP + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &LockHandle->OldIrql); +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +VOID +KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockHandle) +{ +#ifndef CONFIG_SMP + /* Simply raise to synch */ + KeRaiseIrql(SYNCH_LEVEL, &LockHandle->OldIrql); +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +VOID +KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, + IN KIRQL OldIrql) +{ +#ifndef CONFIG_SMP + /* Simply lower IRQL back */ + KeLowerIrql(OldIrql); +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +VOID +KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle) +{ +#ifndef CONFIG_SMP + /* Simply lower IRQL back */ + KeLowerIrql(LockHandle->OldIrql); +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +BOOLEAN +KeTryToAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, + IN PKIRQL OldIrql) +{ +#ifndef CONFIG_SMP + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, OldIrql); + + /* Always return true on UP Machines */ + return TRUE; +#else + UNIMPLEMENTED; +#endif +} + +/* + * @implemented + */ +LOGICAL +KeTryToAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, + OUT PKIRQL OldIrql) +{ +#ifndef CONFIG_SMP + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, OldIrql); + + /* Always return true on UP Machines */ + return TRUE; +#else + UNIMPLEMENTED; +#endif +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ke/amd64/stubs.c b/reactos/ntoskrnl/ke/amd64/stubs.c new file mode 100644 index 00000000000..bfc4545e8fa --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/stubs.c @@ -0,0 +1,188 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * PURPOSE: stubs + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include + +#define NDEBUG +#include + +VOID +FASTCALL +KeZeroPages(IN PVOID Address, + IN ULONG Size) +{ + /* Not using XMMI in this routine */ + RtlZeroMemory(Address, Size); +} + +VOID +FASTCALL +DECLSPEC_NORETURN +KiServiceExit(IN PKTRAP_FRAME TrapFrame, + IN NTSTATUS Status) +{ + UNIMPLEMENTED; +} + +VOID +FASTCALL +DECLSPEC_NORETURN +KiServiceExit2(IN PKTRAP_FRAME TrapFrame) +{ + UNIMPLEMENTED; +} + +BOOLEAN +NTAPI +KeConnectInterrupt(IN PKINTERRUPT Interrupt) +{ + UNIMPLEMENTED; + return FALSE; +} + +PVOID +NTAPI +KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit) +{ + UNIMPLEMENTED; + return NULL; +} + +BOOLEAN +NTAPI +KeSynchronizeExecution( + IN OUT PKINTERRUPT Interrupt, + IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, + IN PVOID SynchronizeContext) +{ + UNIMPLEMENTED; + return FALSE; +} + +NTSTATUS +NTAPI +KeUserModeCallback(IN ULONG RoutineIndex, + IN PVOID Argument, + IN ULONG ArgumentLength, + OUT PVOID *Result, + OUT PULONG ResultLength) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +VOID +KiIdleLoop() +{ + UNIMPLEMENTED; + for(;;); +} + +VOID +NTAPI +KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +KiSwapProcess(IN PKPROCESS NewProcess, + IN PKPROCESS OldProcess) +{ + UNIMPLEMENTED; +} + +VOID +KiSystemService(IN PKTHREAD Thread, + IN PKTRAP_FRAME TrapFrame, + IN ULONG Instruction) +{ + UNIMPLEMENTED; +} + +NTSYSAPI +NTSTATUS +NTAPI +NtCallbackReturn +( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status ) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +NTAPI +NtSetLdtEntries +(ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +NTAPI +NtVdmControl(IN ULONG ControlCode, + IN PVOID ControlData) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +NTAPI +KiCallUserMode( + IN PVOID *OutputBuffer, + IN PULONG OutputLength) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +#undef ExQueryDepthSList +NTKERNELAPI +USHORT +ExQueryDepthSList(IN PSLIST_HEADER ListHead) +{ + return (USHORT)(ListHead->Alignment & 0xffff); +} + + +ULONG ProcessCount; + +#ifdef _MSC_VER +void +__GSHandlerCheck() +{ +} + +int __security_cookie; + +void +__security_check_cookie() +{ +} + +BOOLEAN CcPfEnablePrefetcher; + +unsigned long __readfsdword(const unsigned long Offset) +{ + return 0; +} + +void main() +{ +} + +#endif diff --git a/reactos/ntoskrnl/ke/amd64/thrdini.c b/reactos/ntoskrnl/ke/amd64/thrdini.c new file mode 100644 index 00000000000..616cd303264 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/thrdini.c @@ -0,0 +1,193 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ke/i386/thread.c + * PURPOSE: i386 Thread Context Creation + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +typedef struct _KSWITCHFRAME +{ + PVOID ExceptionList; + BOOLEAN ApcBypassDisable; + PVOID RetAddr; +} KSWITCHFRAME, *PKSWITCHFRAME; + +typedef struct _KSTART_FRAME +{ + PKSYSTEM_ROUTINE SystemRoutine; + PKSTART_ROUTINE StartRoutine; + PVOID StartContext; + BOOLEAN UserThread; +} KSTART_FRAME, *PKSTART_FRAME; + +typedef struct _KUINIT_FRAME +{ + KSWITCHFRAME CtxSwitchFrame; + KSTART_FRAME StartFrame; + KTRAP_FRAME TrapFrame; + //FX_SAVE_AREA FxSaveArea; +} KUINIT_FRAME, *PKUINIT_FRAME; + +typedef struct _KKINIT_FRAME +{ + KSWITCHFRAME CtxSwitchFrame; + KSTART_FRAME StartFrame; + //FX_SAVE_AREA FxSaveArea; +} KKINIT_FRAME, *PKKINIT_FRAME; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +KiInitializeContextThread(IN PKTHREAD Thread, + IN PKSYSTEM_ROUTINE SystemRoutine, + IN PKSTART_ROUTINE StartRoutine, + IN PVOID StartContext, + IN PCONTEXT ContextPointer) +{ + //PFX_SAVE_AREA FxSaveArea; + //PFXSAVE_FORMAT FxSaveFormat; + PKSTART_FRAME StartFrame; + PKSWITCHFRAME CtxSwitchFrame; + PKTRAP_FRAME TrapFrame; + CONTEXT LocalContext; + PCONTEXT Context = NULL; + ULONG ContextFlags; + + /* Check if this is a With-Context Thread */ + if (ContextPointer) + { + /* Set up the Initial Frame */ + PKUINIT_FRAME InitFrame; + InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack - + sizeof(KUINIT_FRAME)); + + /* Copy over the context we got */ + RtlCopyMemory(&LocalContext, ContextPointer, sizeof(CONTEXT)); + Context = &LocalContext; + ContextFlags = CONTEXT_CONTROL; + + /* Zero out the trap frame and save area */ + RtlZeroMemory(&InitFrame->TrapFrame, + KTRAP_FRAME_LENGTH); + + /* Setup the Fx Area */ + //FxSaveArea = &InitFrame->FxSaveArea; + +// /* Get the FX Save Format Area */ +// FxSaveFormat = (PFXSAVE_FORMAT)Context->ExtendedRegisters; +// +// /* Set an initial state */ +// FxSaveFormat->ControlWord = 0x27F; +// FxSaveFormat->StatusWord = 0; +// FxSaveFormat->TagWord = 0; +// FxSaveFormat->ErrorOffset = 0; +// FxSaveFormat->ErrorSelector = 0; +// FxSaveFormat->DataOffset = 0; +// FxSaveFormat->DataSelector = 0; +// FxSaveFormat->MXCsr = 0x1F80; + + /* Set an intial NPX State */ + //Context->FloatSave.Cr0NpxState = 0; + //FxSaveArea->Cr0NpxState = 0; + //FxSaveArea->NpxSavedCpu = 0; + + /* Now set the context flags depending on XMM support */ + //ContextFlags |= (KeI386FxsrPresent) ? CONTEXT_EXTENDED_REGISTERS : + // CONTEXT_FLOATING_POINT; + + /* Set the Thread's NPX State */ + Thread->NpxState = 0xA; + Thread->DispatcherHeader.NpxIrql = PASSIVE_LEVEL; + + /* Disable any debug regiseters */ + Context->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; + + /* Setup the Trap Frame */ + TrapFrame = &InitFrame->TrapFrame; + + /* Set up a trap frame from the context. */ + KeContextToTrapFrame(Context, + NULL, + TrapFrame, + Context->ContextFlags | ContextFlags, + UserMode); + + /* Set SS, DS, ES's RPL Mask properly */ + TrapFrame->SegSs |= RPL_MASK; + TrapFrame->SegDs |= RPL_MASK; + TrapFrame->SegEs |= RPL_MASK; + TrapFrame->Dr7 = 0; + + /* Set the previous mode as user */ + TrapFrame->PreviousMode = UserMode; + + /* Terminate the Exception Handler List */ + TrapFrame->ExceptionFrame = 0; + + /* Setup the Stack for KiThreadStartup and Context Switching */ + StartFrame = &InitFrame->StartFrame; + CtxSwitchFrame = &InitFrame->CtxSwitchFrame; + + /* Tell the thread it will run in User Mode */ + Thread->PreviousMode = UserMode; + + /* Tell KiThreadStartup of that too */ + StartFrame->UserThread = TRUE; + } + else + { + /* Set up the Initial Frame for the system thread */ + PKKINIT_FRAME InitFrame; + InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack - + sizeof(KKINIT_FRAME)); + + /* Setup the Fx Area */ + //FxSaveArea = &InitFrame->FxSaveArea; + //RtlZeroMemory(FxSaveArea, sizeof(FX_SAVE_AREA)); + + /* Check if we have Fxsr support */ + DPRINT1("FxsrPresent but did nothing\n"); +// /* Set the stub FX area */ +// FxSaveArea->U.FxArea.ControlWord = 0x27F; +// FxSaveArea->U.FxArea.MXCsr = 0x1F80; + + /* No NPX State */ + Thread->NpxState = 0xA; + + /* Setup the Stack for KiThreadStartup and Context Switching */ + StartFrame = &InitFrame->StartFrame; + CtxSwitchFrame = &InitFrame->CtxSwitchFrame; + + /* Tell the thread it will run in Kernel Mode */ + Thread->PreviousMode = KernelMode; + + /* Tell KiThreadStartup of that too */ + StartFrame->UserThread = FALSE; + } + + /* Now setup the remaining data for KiThreadStartup */ + StartFrame->StartContext = StartContext; + StartFrame->StartRoutine = StartRoutine; + StartFrame->SystemRoutine = SystemRoutine; + + /* And set up the Context Switch Frame */ + CtxSwitchFrame->RetAddr = KiThreadStartup; + CtxSwitchFrame->ApcBypassDisable = TRUE; + CtxSwitchFrame->ExceptionList = EXCEPTION_CHAIN_END;; + + /* Save back the new value of the kernel stack. */ + Thread->KernelStack = (PVOID)CtxSwitchFrame; + +} + +/* EOF */ + + diff --git a/reactos/ntoskrnl/ke/amd64/trap.S b/reactos/ntoskrnl/ke/amd64/trap.S new file mode 100644 index 00000000000..532f6bbdb91 --- /dev/null +++ b/reactos/ntoskrnl/ke/amd64/trap.S @@ -0,0 +1,948 @@ +/* + * FILE: ntoskrnl/ke/amd64/trap.S + * COPYRIGHT: See COPYING in the top level directory + * PURPOSE: System Traps, Entrypoints and Exitpoints + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#include + +EXTERN KiDispatchException:PROC +EXTERN FrLdrDbgPrint:DWORD +EXTERN KeBugCheckWithTf:PROC +EXTERN MmAccessFault:PROC +EXTERN KiSystemFatalException:PROC +EXTERN KiNpxNotAvailableFaultHandler:PROC +EXTERN KiGeneralProtectionFaultHandler:PROC +EXTERN KiXmmExceptionHandler:PROC + +/* GLOBALS *******************************************************************/ + +.data + +PUBLIC MsgUnimplemented +MsgUnimplemented: +.asciz "WARNING: %s at %s:%d is UNIMPLEMENTED!\n" + +MsgPageFault: +.asciz "Page fault! Code = 0x%x, RIP = %p, FaultingAddress = %p\n" + +MsgGeneralProtFault: +.asciz "General protection fault at %p!\n" + +MsgBreakpointTrap: +.asciz "BreakpointTrap at %p\n" + +MsgUnexpectedInterrupt: +.asciz "UnexpectedInterrupt Vector=0x%02lx\n" + +MsgInvalidOpcodeFault: +.asciz "Invalid opcode fault at %p!\n" + +MsgDoubleFault: +.asciz "Double fault at %p, rbp=%p!\n" + +MsgTrapInfo: +.asciz "Trap: %s at %p\n" + +MACRO(TRAPINFO, func) +LOCAL label1, label2 +#if 0 + jmp label2 +label1: .asciz "\func" +label2: + sub rsp, 32 + lea rcx, MsgTrapInfo[rip] + lea rdx, 1b[rip] + mov r8, [rbp + KTRAP_FRAME_Rip] + call qword ptr FrLdrDbgPrint[rip] + add rsp, 32 +#endif +ENDM + +/* Helper Macros *************************************************************/ + +#define TRAPFLAG_VOLATILES HEX(01) +#define TRAPFLAG_NONVOLATILES HEX(02) +#define TRAPFLAG_XMM HEX(04) +#define TRAPFLAG_SEGMENTS HEX(08) +#define TRAPFLAG_DEBUG HEX(10) +#define TRAPFLAG_HAS_ERRORCODE HEX(100) + +#define TRAPFLAG_SYSTEMSERVICE (TRAPFLAG_VOLATILES|TRAPFLAG_DEBUG) +#define TRAPFLAG_ALL HEX(ff) + +/* + * Stack Layout: + * |-------------------| + * | KTRAP_FRAME | + * |-------------------| <- rbp + * | EXCEPTION_RECORD | + * |-------------------| + * | KEXCEPTION_FRAME | + * |-------------------| <- rsp + * + */ + +/* + * ENTER_TRAP_FRAME - Allocate SIZE_KTRAP_FRAME and save registers to it + */ +MACRO(ENTER_TRAP_FRAME, Flags) +LOCAL dont_swap + + /* Save the trap flags for this trap */ + TRAPFLAGS = VAL(Flags) + + /* Size of hardware trap frame */ +if (TRAPFLAGS AND TRAPFLAG_HAS_ERRORCODE) + .pushframe code + SIZE_INITIAL_FRAME = 6 * 8 +else + .pushframe + SIZE_INITIAL_FRAME = 5 * 8 +endif + + /* Make room for a KTRAP_FRAME */ + sub rsp, (SIZE_KTRAP_FRAME - SIZE_INITIAL_FRAME) + .allocstack (SIZE_KTRAP_FRAME - SIZE_INITIAL_FRAME) + .endprolog + + /* Save rbp */ + mov [rsp + KTRAP_FRAME_Rbp], rbp + + /* Point rbp to the KTRAP_FRAME */ + lea rbp, [rsp] + +if (TRAPFLAGS AND TRAPFLAG_NONVOLATILES) + /* Save non-volatile registers */ + mov [rbp + KTRAP_FRAME_Rbx], rbx + mov [rbp + KTRAP_FRAME_Rdi], rdi + mov [rbp + KTRAP_FRAME_Rsi], rsi +endif + +if (TRAPFLAGS AND TRAPFLAG_VOLATILES) + /* Save volatile registers */ + mov [rbp + KTRAP_FRAME_Rax], rax + mov [rbp + KTRAP_FRAME_Rcx], rcx + mov [rbp + KTRAP_FRAME_Rdx], rdx + mov [rbp + KTRAP_FRAME_R8], r8 + mov [rbp + KTRAP_FRAME_R9], r9 + mov [rbp + KTRAP_FRAME_R10], r10 + mov [rbp + KTRAP_FRAME_R11], r11 +endif + +if (TRAPFLAGS AND TRAPFLAG_XMM) + /* Save xmm registers */ + movdqa [rbp + KTRAP_FRAME_Xmm0], xmm0 + movdqa [rbp + KTRAP_FRAME_Xmm1], xmm1 + movdqa [rbp + KTRAP_FRAME_Xmm2], xmm2 + movdqa [rbp + KTRAP_FRAME_Xmm3], xmm3 + movdqa [rbp + KTRAP_FRAME_Xmm4], xmm4 + movdqa [rbp + KTRAP_FRAME_Xmm5], xmm5 +endif + +if (TRAPFLAGS AND TRAPFLAG_SEGMENTS) + /* Save segment selectors */ + mov ax, ds + mov [rbp + KTRAP_FRAME_SegDs], ax + mov ax, es + mov [rbp + KTRAP_FRAME_SegEs], ax + mov ax, fs + mov [rbp + KTRAP_FRAME_SegFs], ax + mov ax, gs + mov [rbp + KTRAP_FRAME_SegGs], ax +endif + + /* Save previous mode and swap gs when it was UserMode */ + mov ax, [rbp + KTRAP_FRAME_SegCs] + and al, 1 + mov [rbp + KTRAP_FRAME_PreviousMode], al + jz dont_swap + swapgs +dont_swap: + + /* Save previous irql */ + mov rax, cr8 + mov [rbp + KTRAP_FRAME_PreviousIrql], al + +// KTRAP_FRAME_FaultIndicator +// KTRAP_FRAME_ExceptionActive +// KTRAP_FRAME_MxCsr + +if (TRAPFLAGS AND TRAPFLAG_DEBUG) + /* Save debug registers */ + mov rax, dr0 + mov [rbp + KTRAP_FRAME_Dr0], rax + mov rax, dr1 + mov [rbp + KTRAP_FRAME_Dr1], rax + mov rax, dr2 + mov [rbp + KTRAP_FRAME_Dr2], rax + mov rax, dr3 + mov [rbp + KTRAP_FRAME_Dr3], rax + mov rax, dr6 + mov [rbp + KTRAP_FRAME_Dr6], rax + mov rax, dr7 + mov [rbp + KTRAP_FRAME_Dr7], rax +endif + +// KTRAP_FRAME_DebugControl +// KTRAP_FRAME_LastBranchToRip +// KTRAP_FRAME_LastBranchFromRip +// KTRAP_FRAME_LastExceptionToRip +// KTRAP_FRAME_LastExceptionFromRip +// KTRAP_FRAME_TrapFrame + + /* Make sure the direction flag is cleared */ + cld +ENDM + + +/* + * LEAVE_TRAP_FRAME - Restore registers and free stack space + */ +MACRO(LEAVE_TRAP_FRAME) +LOCAL dont_swap_back +if (TRAPFLAGS AND TRAPFLAG_SEGMENTS) + /* Restore segment selectors */ + mov ax, [rbp + KTRAP_FRAME_SegDs] + mov ds, ax + mov ax, [rbp + KTRAP_FRAME_SegEs] + mov es, ax + mov ax, [rbp + KTRAP_FRAME_SegFs] + mov fs, ax +endif + + test byte ptr [rbp + KTRAP_FRAME_PreviousMode], 1 + jz dont_swap_back + swapgs +dont_swap_back: + +if (TRAPFLAGS AND TRAPFLAG_NONVOLATILES) + /* Restore non-volatile registers */ + mov rbx, [rbp + KTRAP_FRAME_Rbx] + mov rdi, [rbp + KTRAP_FRAME_Rdi] + mov rsi, [rbp + KTRAP_FRAME_Rsi] +endif + +if (TRAPFLAGS AND TRAPFLAG_VOLATILES) + /* Restore volatile registers */ + mov rax, [rbp + KTRAP_FRAME_Rax] + mov rcx, [rbp + KTRAP_FRAME_Rcx] + mov rdx, [rbp + KTRAP_FRAME_Rdx] + mov r8, [rbp + KTRAP_FRAME_R8] + mov r9, [rbp + KTRAP_FRAME_R9] + mov r10, [rbp + KTRAP_FRAME_R10] + mov r11, [rbp + KTRAP_FRAME_R11] +endif + +if (TRAPFLAGS AND TRAPFLAG_XMM) + /* Restore xmm registers */ + movdqa xmm0, [rbp + KTRAP_FRAME_Xmm0] + movdqa xmm1, [rbp + KTRAP_FRAME_Xmm1] + movdqa xmm2, [rbp + KTRAP_FRAME_Xmm2] + movdqa xmm3, [rbp + KTRAP_FRAME_Xmm3] + movdqa xmm4, [rbp + KTRAP_FRAME_Xmm4] + movdqa xmm5, [rbp + KTRAP_FRAME_Xmm5] +endif + + /* Restore rbp */ + mov rbp, [rbp + KTRAP_FRAME_Rbp] + + /* Adjust stack pointer */ + add rsp, KTRAP_FRAME_Rip +ENDM + + +/* FUNCTIONS *****************************************************************/ + +.text +.code64 + +ALIGN 8 + +PUBLIC InterruptDispatchTable +InterruptDispatchTable: +Vector = 0 +REPEAT 256 + push Vector + jmp KiUnexpectedInterrupt + ALIGN 8 + Vector = Vector+1 +ENDR + +// rbp = TrapFrame, eax = ExceptionCode, edx = NumParams, r9,r10,r11 = params +.PROC InternalDispatchException + + /* Allocate stack space for EXCEPTION_RECORD and KEXCEPTION_FRAME */ + sub rsp, SIZE_EXCEPTION_RECORD + SIZE_KEXCEPTION_FRAME + .allocstack (SIZE_EXCEPTION_RECORD + SIZE_KEXCEPTION_FRAME) + .endprolog + + /* Set up EXCEPTION_RECORD */ + lea rcx, [rsp + SIZE_KEXCEPTION_FRAME] + mov [rcx + EXCEPTION_RECORD_ExceptionCode], eax + xor rax, rax + mov [rcx + EXCEPTION_RECORD_ExceptionFlags], eax + mov [rcx + EXCEPTION_RECORD_ExceptionRecord], rax + mov rax, [rbp + KTRAP_FRAME_Rip] + mov [rcx + EXCEPTION_RECORD_ExceptionAddress], rax + mov [rcx + EXCEPTION_RECORD_NumberParameters], edx + mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(00)], r9 + mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(08)], r10 + mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(10)], r11 + + /* Set up KEXCEPTION_FRAME */ + mov rax, [rbp + KTRAP_FRAME_Rbp] + mov [rsp + KEXCEPTION_FRAME_Rbp], rax + mov [rsp + KEXCEPTION_FRAME_Rbx], rbx + mov [rsp + KEXCEPTION_FRAME_Rdi], rdi + mov [rsp + KEXCEPTION_FRAME_Rsi], rsi + mov [rsp + KEXCEPTION_FRAME_R12], r12 + mov [rsp + KEXCEPTION_FRAME_R13], r13 + mov [rsp + KEXCEPTION_FRAME_R14], r14 + mov [rsp + KEXCEPTION_FRAME_R15], r15 + movdqa [rsp + KEXCEPTION_FRAME_Xmm6], xmm6 + movdqa [rsp + KEXCEPTION_FRAME_Xmm7], xmm7 + movdqa [rsp + KEXCEPTION_FRAME_Xmm8], xmm8 + movdqa [rsp + KEXCEPTION_FRAME_Xmm9], xmm9 + movdqa [rsp + KEXCEPTION_FRAME_Xmm10], xmm10 + movdqa [rsp + KEXCEPTION_FRAME_Xmm11], xmm11 + movdqa [rsp + KEXCEPTION_FRAME_Xmm12], xmm12 + movdqa [rsp + KEXCEPTION_FRAME_Xmm13], xmm13 + movdqa [rsp + KEXCEPTION_FRAME_Xmm14], xmm14 + movdqa [rsp + KEXCEPTION_FRAME_Xmm15], xmm15 + mov qword ptr [rsp + KEXCEPTION_FRAME_Return], 0 + + /* Call KiDispatchException */ + // rcx already points to ExceptionRecord + mov rdx, rsp // ExceptionFrame + mov r8, rbp // TrapFrame + mov r9b, [r8 + KTRAP_FRAME_PreviousMode] // PreviousMode + mov byte ptr [rsp + KEXCEPTION_FRAME_P5], 1 // FirstChance + call KiDispatchException + + /* Restore registers */ + mov r12, [rsp + KEXCEPTION_FRAME_R12] + mov r13, [rsp + KEXCEPTION_FRAME_R13] + mov r14, [rsp + KEXCEPTION_FRAME_R14] + mov r15, [rsp + KEXCEPTION_FRAME_R15] + movdqa xmm6, [rsp + KEXCEPTION_FRAME_Xmm6] + movdqa xmm7, [rsp + KEXCEPTION_FRAME_Xmm7] + movdqa xmm8, [rsp + KEXCEPTION_FRAME_Xmm8] + movdqa xmm9, [rsp + KEXCEPTION_FRAME_Xmm9] + movdqa xmm10, [rsp + KEXCEPTION_FRAME_Xmm10] + movdqa xmm11, [rsp + KEXCEPTION_FRAME_Xmm11] + movdqa xmm12, [rsp + KEXCEPTION_FRAME_Xmm12] + movdqa xmm13, [rsp + KEXCEPTION_FRAME_Xmm13] + movdqa xmm14, [rsp + KEXCEPTION_FRAME_Xmm14] + movdqa xmm15, [rsp + KEXCEPTION_FRAME_Xmm15] + + add rsp, SIZE_EXCEPTION_RECORD + SIZE_KEXCEPTION_FRAME + ret +.ENDP InternalDispatchException + + +/* SOFTWARE INTERRUPT SERVICES ***********************************************/ + +PUBLIC KiDivideErrorFault +.PROC KiDivideErrorFault + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Enable interrupts */ + sti + + /* Dispatch the exception */ + mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO + mov edx, 0 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiDivideErrorFault + + +PUBLIC KiDebugTrapOrFault +.PROC KiDebugTrapOrFault + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + TRAPINFO KiDebugTrapOrFault + + /* Check if the frame was from kernelmode */ + test word ptr [rbp + KTRAP_FRAME_SegCs], 3 + jz KiDebugTrapOrFaultKMode + + /* Enable interrupts for user-mode */ + sti + +KiDebugTrapOrFaultKMode: + + /* Dispatch the exception */ + mov eax, STATUS_SINGLE_STEP + mov edx, 0 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiDebugTrapOrFault + + +PUBLIC KiNmiInterrupt +.PROC KiNmiInterrupt + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + UNIMPLEMENTED KiNmiInterrupt + + jmp $ + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiNmiInterrupt + + +PUBLIC KiBreakpointTrap +.PROC KiBreakpointTrap + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + TRAPINFO KiBreakpointTrap + +// lea rcx, MsgBreakpointTrap[rip] +// mov rdx, rsp +// call qword ptr FrLdrDbgPrint[rip] + + /* Dispatch the exception */ + mov eax, STATUS_BREAKPOINT + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiBreakpointTrap + + +PUBLIC KiOverflowTrap +.PROC KiOverflowTrap + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Enable interrupts */ + sti + + /* Dispatch the exception */ + mov eax, STATUS_INTEGER_OVERFLOW + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiOverflowTrap + + +PUBLIC KiBoundFault +.PROC KiBoundFault + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Check if the frame was from kernelmode */ + test word ptr [rbp + KTRAP_FRAME_SegCs], 3 + jnz KiBoundFaltUserMode + + /* Bugcheck */ + mov ecx, EXCEPTION_BOUND_CHECK + mov rdx, rbp + call KiSystemFatalException + +KiBoundFaltUserMode: + /* Enable interrupts for user-mode */ + sti + + /* Dispatch the exception */ + mov eax, STATUS_INTEGER_OVERFLOW + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiBoundFault + + +PUBLIC KiInvalidOpcodeFault +.PROC KiInvalidOpcodeFault + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + TRAPINFO KiInvalidOpcodeFault + + mov rdx, [rbp + KTRAP_FRAME_Rip] + lea rcx, MsgInvalidOpcodeFault[rip] + call qword ptr FrLdrDbgPrint[rip] + + /* Enable interrupts */ + sti + + /* Check if the frame was from kernelmode */ + test word ptr [rbp + KTRAP_FRAME_SegCs], 3 + jz KiInvalidOpcodeKernel + + // FIXME: handle STATUS_INVALID_LOCK_SEQUENCE + +KiInvalidOpcodeKernel: + /* Kernel mode fault */ + + /* Dispatch the exception */ + mov eax, STATUS_ILLEGAL_INSTRUCTION + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiInvalidOpcodeFault + + +PUBLIC KiNpxNotAvailableFault +.PROC KiNpxNotAvailableFault + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Call the C handler */ + mov rcx, rbp + call KiNpxNotAvailableFaultHandler + + /* Check the return status code */ + test eax, eax + jz KiNpxNotAvailableFaultExit + + /* Dispatch the exception */ + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + +KiNpxNotAvailableFaultExit: + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiNpxNotAvailableFault + + +PUBLIC KiDoubleFaultAbort +.PROC KiDoubleFaultAbort + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + lea rcx, MsgDoubleFault[rip] + mov rdx, [rbp + KTRAP_FRAME_FaultAddress] + mov r8, rbp + call qword ptr FrLdrDbgPrint[rip] + + /* Bugcheck */ + mov ecx, 8 // EXCEPTION_DOUBLE_FAULT + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiDoubleFaultAbort + + +PUBLIC KiNpxSegmentOverrunAbort +.PROC KiNpxSegmentOverrunAbort + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Bugcheck */ + mov ecx, EXCEPTION_NPX_OVERRUN + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiNpxSegmentOverrunAbort + + +PUBLIC KiInvalidTssFault +.PROC KiInvalidTssFault + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + /* Bugcheck */ + mov ecx, EXCEPTION_INVALID_TSS + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiInvalidTssFault + + +PUBLIC KiSegmentNotPresentFault +.PROC KiSegmentNotPresentFault + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + /* Bugcheck */ + mov ecx, EXCEPTION_SEGMENT_NOT_PRESENT + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiSegmentNotPresentFault + + +PUBLIC KiStackFault +.PROC KiStackFault + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + /* Bugcheck */ + mov ecx, EXCEPTION_STACK_FAULT + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiStackFault + + +PUBLIC KiGeneralProtectionFault +.PROC KiGeneralProtectionFault + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + TRAPINFO KiGeneralProtectionFault + mov rdx, [rbp + KTRAP_FRAME_Rip] + lea rcx, MsgGeneralProtFault[rip] + call qword ptr FrLdrDbgPrint[rip] + + /* Call the C handler */ + call KiGeneralProtectionFaultHandler + + /* Check for success */ + test eax, eax + jge KiGpfExit + + /* Dispatch the exception */ + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + +KiGpfFatal: + + /* Bugcheck */ + mov ecx, UNEXPECTED_KERNEL_MODE_TRAP + mov rdx, HEX(000D) // EXCEPTION_GP_FAULT + xor r8, r8 + mov r9, [rbp + KTRAP_FRAME_ErrorCode] // error code + sub rsp, 8 + mov [rsp + KTRAP_FRAME_P5+8], rbp // trap frame + call KeBugCheckWithTf + +KiGpfExit: + /* Return */ + LEAVE_TRAP_FRAME + iretq +.ENDP KiGeneralProtectionFault + + +PUBLIC KiPageFault +.PROC KiPageFault + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + TRAPINFO KiPageFault + +#if 0 + lea rcx, MsgPageFault[rip] + mov rdx, [rbp + KTRAP_FRAME_ErrorCode] + mov r8, [rbp + KTRAP_FRAME_Rip] + mov r9, [rbp + KTRAP_FRAME_FaultAddress] + call qword ptr FrLdrDbgPrint[rip] +#endif + + /* Save page fault address */ + mov rdx, cr2 + mov [rbp + KTRAP_FRAME_FaultAddress], rdx + + /* Call page fault handler */ + mov ecx, [rbp + KTRAP_FRAME_ErrorCode] // StoreInstruction + and ecx, 1 + // rdx == Address + mov r8b, [rbp + KTRAP_FRAME_SegCs] // Mode + and r8b, 1 + mov r9, rbp // TrapInformation + call MmAccessFault + + /* Check for success */ + test eax, eax + jge PageFaultReturn + + /* Set parameter 1 to error code */ + mov r9d, [rbp + KTRAP_FRAME_ErrorCode] + + /* Set parameter2 to faulting address */ + mov r10, cr2 // Param2 = faulting address + + cmp eax, STATUS_ACCESS_VIOLATION + je AccessViolation + cmp eax, STATUS_GUARD_PAGE_VIOLATION + je SpecialCode + cmp eax, STATUS_STACK_OVERFLOW + je SpecialCode + +InPageException: + /* Dispatch in-page exception */ + mov r11d, eax // Param3 = Status + mov eax, STATUS_IN_PAGE_ERROR // ExceptionCode + mov edx, 3 // ParamCount + call InternalDispatchException + jmp PageFaultReturn + +AccessViolation: + /* Use more proper status code */ + mov eax, KI_EXCEPTION_ACCESS_VIOLATION + +SpecialCode: + /* Setup a normal page fault exception */ + mov edx, 2 // ParamCount + call InternalDispatchException + +PageFaultReturn: + LEAVE_TRAP_FRAME + iretq +.ENDP KiPageFault + + +PUBLIC KiFloatingErrorFault +.PROC KiFloatingErrorFault + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + UNIMPLEMENTED KiFloatingErrorFault + + jmp $ +.ENDP KiFloatingErrorFault + + +PUBLIC KiAlignmentFault +.PROC KiAlignmentFault + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + /* Enable interrupts */ + sti + + /* Bugcheck */ + mov ecx, EXCEPTION_ALIGNMENT_CHECK + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiAlignmentFault + + +PUBLIC KiMcheckAbort +.PROC KiMcheckAbort + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Bugcheck */ + mov ecx, HEX(12) + mov rdx, rbp + call KiSystemFatalException + + jmp $ +.ENDP KiMcheckAbort + + +PUBLIC KiXmmException +.PROC KiXmmException + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + /* Call the C handler */ + mov rcx, rbp + call KiXmmExceptionHandler + + /* Check for success */ + test eax, eax + jge KiXmmExit + + /* Dispatch the exception */ + mov edx, 3 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + +KiXmmExit: + LEAVE_TRAP_FRAME + iretq +.ENDP KiXmmException + + +PUBLIC KiApcInterrupt +.PROC KiApcInterrupt + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + UNIMPLEMENTED KiApcInterrupt + + jmp $ +.ENDP KiApcInterrupt + + +PUBLIC KiRaiseAssertion +.PROC KiRaiseAssertion + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + /* Decrement RIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */ + sub qword ptr [rbp + KTRAP_FRAME_Rip], 2 + + /* Dispatch the exception */ + mov eax, STATUS_ASSERTION_FAILURE + mov edx, 0 + mov r9, 0 + mov r10, 0 + mov r11, 0 + call InternalDispatchException + + LEAVE_TRAP_FRAME + iretq +.ENDP KiRaiseAssertion + + +PUBLIC KiDebugServiceTrap +.PROC KiDebugServiceTrap + /* Push pseudo error code */ + ENTER_TRAP_FRAME TRAPFLAG_ALL + + TRAPINFO KiDebugServiceTrap + + /* Increase Rip to skip the int3 */ + inc qword ptr [rbp + KTRAP_FRAME_Rip] + + /* Dispatch the exception */ + mov eax, STATUS_BREAKPOINT + mov edx, 3 + mov r9, [rbp+KTRAP_FRAME_Rax] // Service + mov r10, [rbp+KTRAP_FRAME_Rcx] // Buffer + mov r11, [rbp+KTRAP_FRAME_Rdx] // Length + call InternalDispatchException + + LEAVE_TRAP_FRAME; + iretq +.ENDP KiDebugServiceTrap + + +PUBLIC KiDpcInterrupt +.PROC KiDpcInterrupt + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + UNIMPLEMENTED KiDpcInterrupt + + jmp $ +.ENDP KiDpcInterrupt + + +PUBLIC KiIpiInterrupt +.PROC KiIpiInterrupt + /* We have an error code */ + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + UNIMPLEMENTED KiIpiInterrupt + + jmp $ +.ENDP KiIpiInterrupt + + +PUBLIC KiUnexpectedInterrupt +.PROC KiUnexpectedInterrupt + /* The error code is the vector */ + cli + ENTER_TRAP_FRAME (TRAPFLAG_HAS_ERRORCODE OR TRAPFLAG_ALL) + + /* Set bugcheck parameters */ + mov ecx, TRAP_CAUSE_UNKNOWN + mov rdx, [rbp + KTRAP_FRAME_ErrorCode] // the vector + mov r8, 0 // The unknown floating-point exception + mov r9, 0 // The enabled and asserted status bits + sub rsp, 8 + mov [rbp + KTRAP_FRAME_P5 + 8], rbp // trap frame + call KeBugCheckWithTf + + jmp $ +.ENDP KiUnexpectedInterrupt + +#ifdef _MSC_VER + +//void __lgdt(void *Source); +PUBLIC __lgdt +__lgdt: + lgdt fword ptr [rcx] + ret + +//void __sgdt(void *Destination); +PUBLIC __sgdt +__sgdt: + sgdt fword ptr [rcx] + ret + +// void __lldt(unsigned short Value) +PUBLIC __lldt +__lldt: + lldt cx + ret + +//void __sldt(void *Destination); +PUBLIC __sldt +__sldt: + sldt word ptr [rcx] + ret + +//void __ltr(unsigned short Source); +PUBLIC __ltr +__ltr: + ltr cx + ret + +//void __str(unsigned short *Destination); +PUBLIC __str +__str: + str word ptr [rcx] + ret + +#endif + +END diff --git a/reactos/ntoskrnl/mm/amd64/init.c b/reactos/ntoskrnl/mm/amd64/init.c new file mode 100644 index 00000000000..eab7192edfc --- /dev/null +++ b/reactos/ntoskrnl/mm/amd64/init.c @@ -0,0 +1,884 @@ +/* + * COPYRIGHT: GPL, See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/amd64/init.c + * PURPOSE: Memory Manager Initialization for amd64 + * + * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org) + * ReactOS Portable Systems Group + */ + +/* INCLUDES ***************************************************************/ + +#include +//#define NDEBUG +#include + +#include "../ARM3/miarm.h" + +#ifdef _WINKD_ +extern PMMPTE MmDebugPte; +#endif + +VOID +NTAPI +HalInitializeBios(ULONG Unknown, PLOADER_PARAMETER_BLOCK LoaderBlock); + +/* GLOBALS *****************************************************************/ + +/* Template PTE and PDE for a kernel page */ +MMPTE ValidKernelPde = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1, .u.Hard.Accessed = 1}; +MMPTE ValidKernelPte = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1, .u.Hard.Accessed = 1}; +MMPDE DemandZeroPde = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS)}; +MMPTE PrototypePte = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | PTE_PROTOTYPE | 0xFFFFF000}; + +/* Sizes */ +///SIZE_T MmSessionSize = MI_SESSION_SIZE; +SIZE_T MmSessionViewSize = MI_SESSION_VIEW_SIZE; +SIZE_T MmSessionPoolSize = MI_SESSION_POOL_SIZE; +SIZE_T MmSessionImageSize = MI_SESSION_IMAGE_SIZE; +SIZE_T MmSystemViewSize = MI_SYSTEM_VIEW_SIZE; +SIZE_T MiNonPagedSystemSize; + +/* Address ranges */ +ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL; +PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL; +PVOID MmSystemRangeStart = (PVOID)0xFFFF080000000000ULL; +PVOID MmSessionBase; // FFFFF90000000000 = MiSessionPoolStart +PVOID MiSessionPoolStart; // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize +PVOID MiSessionPoolEnd; // = MiSessionViewStart +PVOID MiSessionViewStart; // = MiSessionViewEnd - MmSessionViewSize +PVOID MiSessionViewEnd; // FFFFF97FFF000000 +PVOID MiSessionImageStart; // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize +PVOID MiSessionImageEnd; // FFFFF98000000000 = MiSessionSpaceEnd +PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000 +PVOID MmSystemCacheStart; // FFFFF98000000000 +PVOID MmSystemCacheEnd; // FFFFFA8000000000 +/// PVOID MmPagedPoolStart = MI_PAGED_POOL_START; // FFFFFA8000000000 +PVOID MmPagedPoolEnd; // FFFFFAA000000000 +PVOID MiSystemViewStart; +PVOID MmNonPagedSystemStart; // FFFFFAA000000000 +PVOID MmNonPagedPoolStart; +PVOID MmNonPagedPoolExpansionStart; +///PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END; // 0xFFFFFAE000000000 +PVOID MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END; + +MMSUPPORT MmSystemCacheWs; + +ULONG64 MxPfnSizeInBytes; + +PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor; +MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor; +ULONG MiNumberDescriptors = 0; +PFN_NUMBER MiSystemPages = 0; +BOOLEAN MiIncludeType[LoaderMaximum]; + +PFN_NUMBER MxFreePageBase; +ULONG64 MxFreePageCount = 0; + +extern PFN_NUMBER MmSystemPageDirectory[PD_COUNT]; + +BOOLEAN MiPfnsInitialized = FALSE; + +/* FUNCTIONS *****************************************************************/ + +ULONG +NoDbgPrint(const char *Format, ...) +{ + return 0; +} + +VOID +NTAPI +MiEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY ListEntry; + PFN_NUMBER LastPage; + ULONG i; + + /* Get the size of the boot loader's image allocations */ + MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE; + MmBootImageSize = ROUND_UP(MmBootImageSize, 4 * 1024 * 1024); + + /* Instantiate memory that we don't consider RAM/usable */ + for (i = 0; i < LoaderMaximum; i++) MiIncludeType[i] = TRUE; + MiIncludeType[LoaderBad] = FALSE; + MiIncludeType[LoaderFirmwarePermanent] = FALSE; + MiIncludeType[LoaderSpecialMemory] = FALSE; + MiIncludeType[LoaderBBTMemory] = FALSE; + + /* Loop the memory descriptors */ + for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; + ListEntry != &LoaderBlock->MemoryDescriptorListHead; + ListEntry = ListEntry->Flink) + { + /* Get the memory descriptor */ + Descriptor = CONTAINING_RECORD(ListEntry, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + /* Count it */ + MiNumberDescriptors++; + + /* Skip pages that are not part of the PFN database */ + if (!MiIncludeType[Descriptor->MemoryType]) + { + continue; + } + + /* Add this to the total of pages */ + MmNumberOfPhysicalPages += Descriptor->PageCount; + + /* Check if this is the new lowest page */ + if (Descriptor->BasePage < MmLowestPhysicalPage) + { + /* Update the lowest page */ + MmLowestPhysicalPage = Descriptor->BasePage; + } + + /* Check if this is the new highest page */ + LastPage = Descriptor->BasePage + Descriptor->PageCount - 1; + if (LastPage > MmHighestPhysicalPage) + { + /* Update the highest page */ + MmHighestPhysicalPage = LastPage; + } + + /* Check if this is currently free memory */ + if ((Descriptor->MemoryType == LoaderFree) || + (Descriptor->MemoryType == LoaderLoadedProgram) || + (Descriptor->MemoryType == LoaderFirmwareTemporary) || + (Descriptor->MemoryType == LoaderOsloaderStack)) + { + /* Check if this is the largest memory descriptor */ + if (Descriptor->PageCount > MxFreePageCount) + { + /* For now, it is */ + MxFreeDescriptor = Descriptor; + MxFreePageBase = Descriptor->BasePage; + MxFreePageCount = Descriptor->PageCount; + } + } + else + { + /* Add it to the amount of system used pages */ + MiSystemPages += Descriptor->PageCount; + } + } +} + +PFN_NUMBER +NTAPI +MiEarlyAllocPage() +{ + PFN_NUMBER Pfn; + + if (MiPfnsInitialized) + { + return MmAllocPage(MC_SYSTEM); + } + + /* Make sure we have enough pages */ + if (!MxFreePageCount) + { + /* Crash the system */ + KeBugCheckEx(INSTALL_MORE_MEMORY, + MmNumberOfPhysicalPages, + MxFreeDescriptor->PageCount, + MxOldFreeDescriptor.PageCount, + 1); + } + + /* Use our lowest usable free pages */ + Pfn = MxFreePageBase; + MxFreePageBase++; + MxFreePageCount--; + return Pfn; +} + +PMMPTE +NTAPI +MxGetPte(PVOID Address) +{ + PMMPTE Pte; + MMPTE TmplPte; + + /* Setup template pte */ + TmplPte.u.Long = 0; + TmplPte.u.Flush.Valid = 1; + TmplPte.u.Flush.Write = 1; + + /* Get a pointer to the PXE */ + Pte = MiAddressToPxe(Address); + if (!Pte->u.Hard.Valid) + { + /* It's not valid, map it! */ + TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage(); + *Pte = TmplPte; + + /* Zero the page */ + RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE); + } + + /* Get a pointer to the PPE */ + Pte = MiAddressToPpe(Address); + if (!Pte->u.Hard.Valid) + { + /* It's not valid, map it! */ + TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage(); + *Pte = TmplPte; + + /* Zero the page */ + RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE); + } + + /* Get a pointer to the PDE */ + Pte = MiAddressToPde(Address); + if (!Pte->u.Hard.Valid) + { + /* It's not valid, map it! */ + TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage(); + *Pte = TmplPte; + + /* Zero the page */ + RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE); + } + + /* Get a pointer to the PTE */ + Pte = MiAddressToPte(Address); + return Pte; +} + +VOID +NTAPI +MxMapPage(PVOID Address) +{ + MMPTE TmplPte, *Pte; + + /* Setup template pte */ + TmplPte.u.Long = 0; + TmplPte.u.Flush.Valid = 1; + TmplPte.u.Flush.Write = 1; + TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage(); + + /* Get the PTE for that page */ + Pte = MxGetPte(Address); + ASSERT(Pte->u.Hard.Valid == 0); + + /* Map a physical page */ + *Pte = TmplPte; +} + +VOID +MxMapPageRange(PVOID Address, ULONG64 PageCount) +{ + while (PageCount--) + { + /* Map the page */ + MxMapPage(Address); + + /* Goto next page */ + Address = (PVOID)((ULONG64)Address + PAGE_SIZE); + } +} + +VOID +NTAPI +MiPreparePfnDatabse(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY ListEntry; + PUCHAR Page, FirstPage; + SIZE_T Size; + + /* Calculate the size of the PFN database and convert to pages */ + MxPfnSizeInBytes = ROUND_TO_PAGES((MmHighestPhysicalPage + 1) * sizeof(MMPFN)); + MxPfnAllocation = MxPfnSizeInBytes >> PAGE_SHIFT; + + /* Simply start at hardcoded address */ + MmPfnDatabase = MI_PFN_DATABASE; + + /* Loop the memory descriptors */ + for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; + ListEntry != &LoaderBlock->MemoryDescriptorListHead; + ListEntry = ListEntry->Flink) + { + /* Get the memory descriptor */ + Descriptor = CONTAINING_RECORD(ListEntry, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + /* Skip pages that are not part of the PFN database */ + if (MiIncludeType[Descriptor->MemoryType]) + { + /* Get the base and size of this pfn database entry */ + FirstPage = PAGE_ALIGN(&MmPfnDatabase[Descriptor->BasePage]); + Size = ROUND_TO_PAGES(Descriptor->PageCount * sizeof(MMPFN)); + + /* Loop the pages of this Pfn database entry */ + for (Page = FirstPage; Page < FirstPage + Size; Page += PAGE_SIZE) + { + /* Is the page already mapped? */ + if (!MmIsAddressValid(Page)) + { + /* It's not, map it now */ + MxMapPage(Page); + RtlZeroMemory(Page, PAGE_SIZE); + } + } + + /* Zero out the pages */ + RtlZeroMemory(FirstPage, Size); + } + } +} + + +VOID +NTAPI +MiInitializeSessionSpace(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + /* Set up session space */ + MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END; + + /* This is where we will load Win32k.sys and the video driver */ + MiSessionImageEnd = MiSessionSpaceEnd; + MiSessionImageStart = (PCHAR)MiSessionImageEnd - MmSessionImageSize; + + /* The view starts right below the session working set (itself below + * the image area) */ + MiSessionViewEnd = MI_SESSION_VIEW_END; + MiSessionViewStart = (PCHAR)MiSessionViewEnd - MmSessionViewSize; + ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart)); + + /* Session pool follows */ + MiSessionPoolEnd = MiSessionViewStart; + MiSessionPoolStart = (PCHAR)MiSessionPoolEnd - MmSessionPoolSize; + ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart)); + + /* And it all begins here */ + MmSessionBase = MiSessionPoolStart; + + /* System view space ends at session space, so now that we know where + * this is, we can compute the base address of system view space itself. */ + MiSystemViewStart = (PCHAR)MmSessionBase - MmSystemViewSize; + ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart)); + + /* Sanity checks */ + ASSERT(MiSessionViewEnd <= MiSessionImageStart); + ASSERT(MmSessionBase <= MiSessionPoolStart); +} + +VOID +MiInitializePageTable() +{ + ULONG64 PageFrameOffset; + MMPTE TmplPte, *Pte; + + /* HACK: don't use freeldr debug print anymore */ + //FrLdrDbgPrint = NoDbgPrint; + + /* Get current directory base */ + MmSystemPageDirectory[0] = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber; + PageFrameOffset = MmSystemPageDirectory[0] << PAGE_SHIFT; + ASSERT(PageFrameOffset == __readcr3()); + + /* Set directory base for the system process */ + PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset; + + /* Enable global pages */ + __writecr4(__readcr4() | CR4_PGE); + ASSERT(__readcr4() & CR4_PGE); + + /* Enable no execute */ + __writemsr(X86_MSR_EFER, __readmsr(X86_MSR_EFER) | EFER_NXE); + + /* Loop the user mode PXEs */ + for (Pte = MiAddressToPxe(0); + Pte <= MiAddressToPxe(MmHighestUserAddress); + Pte++) + { + /* Zero the PXE, clear all mappings */ + Pte->u.Long = 0; + } + + /* Flush the TLB */ + KeFlushCurrentTb(); + + /* Set up a template PTE */ + TmplPte.u.Long = 0; + TmplPte.u.Flush.Valid = 1; + TmplPte.u.Flush.Write = 1; + HyperTemplatePte = TmplPte; + + /* Create PDPTs (72 KB) for shared system address space, + * skip page tables and hyperspace */ + + /* Loop the PXEs */ + for (Pte = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1)); + Pte <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS); + Pte++) + { + /* Is the PXE already valid? */ + if (!Pte->u.Hard.Valid) + { + /* It's not Initialize it */ + TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage(0); + *Pte = TmplPte; + + /* Zero the page. The PXE is the PTE for the PDPT. */ + RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE); + } + } + + /* Setup the mapping PTEs */ + MmFirstReservedMappingPte = MxGetPte((PVOID)MI_MAPPING_RANGE_START); + MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES; + MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END); + +#ifdef _WINKD_ + /* Setup debug mapping PTE */ + MmDebugPte = MxGetPte(MI_DEBUG_MAPPING); +#endif +} + +VOID +NTAPI +MiBuildNonPagedPool(VOID) +{ + PMMPTE Pte; + PFN_COUNT PageCount; + + /* Check if this is a machine with less than 256MB of RAM, and no overide */ + if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) && + !(MmSizeOfNonPagedPoolInBytes)) + { + /* Force the non paged pool to be 2MB so we can reduce RAM usage */ + MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024; + } + + /* Check if the user gave a ridicuously large nonpaged pool RAM size */ + if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) > + (MmNumberOfPhysicalPages * 7 / 8)) + { + /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */ + MmSizeOfNonPagedPoolInBytes = 0; + } + + /* Check if no registry setting was set, or if the setting was too low */ + if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize) + { + /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */ + MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize; + MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) / + 256 * MmMinAdditionNonPagedPoolPerMb; + } + + /* Check if the registy setting or our dynamic calculation was too high */ + if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE) + { + /* Set it to the maximum */ + MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE; + } + + /* Check if a percentage cap was set through the registry */ + if (MmMaximumNonPagedPoolPercent) + { + /* Don't feel like supporting this right now */ + UNIMPLEMENTED; + } + + /* Page-align the nonpaged pool size */ + MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1); + + /* Now, check if there was a registry size for the maximum size */ + if (!MmMaximumNonPagedPoolInBytes) + { + /* Start with the default (1MB) and add 400 KB for each MB above 4 */ + MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool; + MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) / + 256 * MmMaxAdditionNonPagedPoolPerMb; + } + + /* Don't let the maximum go too high */ + if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE) + { + /* Set it to the upper limit */ + MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE; + } + + /* Put non paged pool to the end of the region */ + MmNonPagedPoolStart = (PCHAR)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes; + + /* Make sure it doesn't collide with the PFN database */ + if ((PCHAR)MmNonPagedPoolStart < (PCHAR)MmPfnDatabase + MxPfnSizeInBytes) + { + /* Put non paged pool after the PFN database */ + MmNonPagedPoolStart = (PCHAR)MmPfnDatabase + MxPfnSizeInBytes; + MmMaximumNonPagedPoolInBytes = (ULONG64)MmNonPagedPoolEnd - + (ULONG64)MmNonPagedPoolStart; + } + + ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart)); + + /* Calculate the nonpaged pool expansion start region */ + MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart + + MmSizeOfNonPagedPoolInBytes; + ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart)); + + /* Map the nonpaged pool */ + PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE; + MxMapPageRange(MmNonPagedPoolStart, PageCount); + + /* Loop the non paged pool extension PTEs */ + for (Pte = MiAddressToPte(MmNonPagedPoolExpansionStart); + Pte <= MiAddressToPte(MmNonPagedPoolEnd); + Pte++) + { + /* Create PXE, PPE, PDE and zero the PTE */ + MxGetPte(MiPteToAddress(Pte))->u.Long = 0; + } + + /* Initialize the ARM3 nonpaged pool */ + MiInitializeNonPagedPool(); + + /* Initialize the nonpaged pool */ + InitializePool(NonPagedPool, 0); +} + +VOID +NTAPI +MiBuildSystemPteSpace() +{ + PMMPTE Pte, StartPte, EndPte; + + /* Use the default numer of system PTEs */ + MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES; + + /* System PTE pool is below the PFN database */ + MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE; + MmNonPagedSystemStart = (PCHAR)MmPfnDatabase - MiNonPagedSystemSize; + MmNonPagedSystemStart = MM_ROUND_DOWN(MmNonPagedSystemStart, 512 * PAGE_SIZE); + + /* Don't let it go below the minimum */ + if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN) + { + /* This is a hard-coded limit in the Windows NT address space */ + MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN; + + /* Reduce the amount of system PTEs to reach this point */ + MmNumberOfSystemPtes = ((ULONG64)MmPfnDatabase - + (ULONG64)MmNonPagedSystemStart) >> + PAGE_SHIFT; + MmNumberOfSystemPtes--; + ASSERT(MmNumberOfSystemPtes > 1000); + } + + /* Set the range of system PTEs */ + StartPte = MiAddressToPte(MI_SYSTEM_PTE_START); + EndPte = StartPte + MmNumberOfSystemPtes - 1; + + /* Loop the system PTEs */ + for (Pte = StartPte; Pte <= EndPte; Pte++) + { + /* Create PXE, PPE, PDE and zero the PTE */ + MxGetPte(MiPteToAddress(Pte))->u.Long = 0; + } + + /* Create the system PTE space */ + Pte = MiAddressToPte(MI_SYSTEM_PTE_START); + MiInitializeSystemPtes(Pte, MmNumberOfSystemPtes, SystemPteSpace); + + /* Reserve system PTEs for zeroing PTEs and clear them */ + MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES, SystemPteSpace); + RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE)); + + /* Set the counter to maximum */ + MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1; +} + +VOID +NTAPI +MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PPHYSICAL_MEMORY_DESCRIPTOR Buffer; + PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; + PLIST_ENTRY ListEntry; + PFN_NUMBER NextPage = -1; + PULONG Bitmap; + ULONG Runs = 0; + ULONG Size; + + /* Calculate size for the PFN bitmap */ + Size = ROUND_UP(MmHighestPhysicalPage + 1, sizeof(ULONG)); + + /* Allocate the PFN bitmap */ + Bitmap = ExAllocatePoolWithTag(NonPagedPool, Size, ' mM'); + + /* Allocate enough memory for the physical memory block */ + Buffer = ExAllocatePoolWithTag(NonPagedPool, + sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + + sizeof(PHYSICAL_MEMORY_RUN) * + (MiNumberDescriptors - 1), + 'lMmM'); + if (!Bitmap || !Buffer) + { + /* This is critical */ + KeBugCheckEx(INSTALL_MORE_MEMORY, + MmNumberOfPhysicalPages, + MmLowestPhysicalPage, + MmHighestPhysicalPage, + 0x101); + } + + /* Initialize the bitmap and clear all bits */ + RtlInitializeBitMap(&MiPfnBitMap, Bitmap, MmHighestPhysicalPage + 1); + RtlClearAllBits(&MiPfnBitMap); + + /* Loop the memory descriptors */ + for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; + ListEntry != &LoaderBlock->MemoryDescriptorListHead; + ListEntry = ListEntry->Flink) + { + /* Get the memory descriptor */ + Descriptor = CONTAINING_RECORD(ListEntry, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + /* Skip pages that are not part of the PFN database */ + if (!MiIncludeType[Descriptor->MemoryType]) + { + continue; + } + + /* Does the memory block begin where the last ended? */ + if (Descriptor->BasePage == NextPage) + { + /* Add it to the current run */ + Buffer->Run[Runs - 1].PageCount += Descriptor->PageCount; + } + else + { + /* Create a new run */ + Runs++; + Buffer->Run[Runs - 1].BasePage = Descriptor->BasePage; + Buffer->Run[Runs - 1].PageCount = Descriptor->PageCount; + } + + /* Set the bits in the PFN bitmap */ + RtlSetBits(&MiPfnBitMap, Descriptor->BasePage, Descriptor->PageCount); + + /* Set the next page */ + NextPage = Descriptor->BasePage + Descriptor->PageCount; + } + + // FIXME: allocate a buffer of better size + + Buffer->NumberOfRuns = Runs; + Buffer->NumberOfPages = MmNumberOfPhysicalPages; + MmPhysicalMemoryBlock = Buffer; +} + +VOID +NTAPI +MiBuildPagedPool_x(VOID) +{ + PMMPTE Pte; + MMPTE TmplPte; + ULONG Size, BitMapSize; + + /* Default size for paged pool is 4 times non paged pool */ + MmSizeOfPagedPoolInBytes = 4 * MmMaximumNonPagedPoolInBytes; + + /* Make sure it doesn't overflow */ + if (MmSizeOfPagedPoolInBytes > ((ULONG64)MmNonPagedSystemStart - + (ULONG64)MmPagedPoolStart)) + { + MmSizeOfPagedPoolInBytes = (ULONG64)MmNonPagedSystemStart - + (ULONG64)MmPagedPoolStart; + } + + /* Make sure paged pool is big enough */ + if (MmSizeOfPagedPoolInBytes < MI_MIN_INIT_PAGED_POOLSIZE) + { + MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE; + } + + /* Align down to a PDE boundary */ + MmSizeOfPagedPoolInBytes = ROUND_DOWN(MmSizeOfPagedPoolInBytes, + 512 * PAGE_SIZE); + MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT; + + /* This is where paged pool ends */ + MmPagedPoolEnd = (PCHAR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes - 1; + + /* Sanity check */ + ASSERT(MmPagedPoolEnd < MmNonPagedSystemStart); + + /* setup a template PTE */ + TmplPte.u.Long = 0; + TmplPte.u.Flush.Valid = 1; + TmplPte.u.Flush.Write = 1; + + /* Make sure the PXE is valid */ + Pte = MiAddressToPxe(MmPagedPoolStart); + if (!Pte->u.Flush.Valid) + { + /* Map it! */ + TmplPte.u.Flush.PageFrameNumber = MmAllocPage(MC_SYSTEM); + *Pte = TmplPte; + } + + /* Map all page directories (max 128) */ + for (Pte = MiAddressToPpe(MmPagedPoolStart); + Pte <= MiAddressToPpe(MmPagedPoolEnd); + Pte++) + { + if (!Pte->u.Flush.Valid) + { + /* Map it! */ + TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage(); + *Pte = TmplPte; + } + } + + /* Create and map the first PTE for paged pool */ + Pte = MxGetPte(MmPagedPoolStart); + TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage(); + *Pte = TmplPte; + + /* Save the first and last paged pool PTE */ + MmPagedPoolInfo.FirstPteForPagedPool = MiAddressToPte(MmPagedPoolStart); + MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd); + + MmPagedPoolInfo.NextPdeForPagedPoolExpansion = + MiAddressToPde(MmPagedPoolStart) + 1; + + // We keep track of each page via a bit, so check how big the bitmap will + // have to be (make sure to align our page count such that it fits nicely + // into a 4-byte aligned bitmap. + + /* The size of the bitmap in bits is the size in pages */ + BitMapSize = MmSizeOfPagedPoolInPages; + + /* Calculate buffer size in bytes, aligned to 32 bits */ + Size = sizeof(RTL_BITMAP) + ROUND_UP(BitMapSize, 32) / 8; + + // Allocate the allocation bitmap, which tells us which regions have not yet + // been mapped into memory + + MmPagedPoolInfo.PagedPoolAllocationMap = + ExAllocatePoolWithTag(NonPagedPool, Size, ' mM'); + ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap); + + // Initialize it such that at first, only the first page's worth of PTEs is + // marked as allocated (incidentially, the first PDE we allocated earlier). + RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap, + (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1), + BitMapSize); + RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap); + RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 512); + + // We have a second bitmap, which keeps track of where allocations end. + // Given the allocation bitmap and a base address, we can therefore figure + // out which page is the last page of that allocation, and thus how big the + // entire allocation is. + MmPagedPoolInfo.EndOfPagedPoolBitmap = + ExAllocatePoolWithTag(NonPagedPool, Size, ' mM'); + ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap); + + /* Initialize the bitmap */ + RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap, + (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1), + BitMapSize); + + /* No allocations, no allocation ends; clear all bits. */ + RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap); + + /* Initialize the paged pool mutex */ + KeInitializeGuardedMutex(&MmPagedPoolMutex); + + /* Initialize the paged pool */ + InitializePool(PagedPool, 0); +} + + +NTSTATUS +NTAPI +MmArmInitSystem_x(IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + if (Phase == 0) + { + MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE; + MmBootImageSize = ROUND_UP(MmBootImageSize, PAGE_SIZE); + + /* Parse memory descriptors, find free pages */ + MiEvaluateMemoryDescriptors(LoaderBlock); + + /* Start PFN database at hardcoded address */ + MmPfnDatabase = MI_PFN_DATABASE; + + /* Prepare PFN database mappings */ + MiPreparePfnDatabse(LoaderBlock); + + /* Initialize the session space */ + MiInitializeSessionSpace(LoaderBlock); + + /* Initialize some mappings */ + MiInitializePageTable(); + + /* Update the memory descriptor, to make sure the pages we used + won't get inserted into the PFN database */ + MxOldFreeDescriptor = *MxFreeDescriptor; + MxFreeDescriptor->BasePage = MxFreePageBase; + MxFreeDescriptor->PageCount = MxFreePageCount; + } + else if (Phase == 1) + { + /* The PFN database was created, restore the free descriptor */ + *MxFreeDescriptor = MxOldFreeDescriptor; + + /* The pfn database is ready now */ + MiPfnsInitialized = TRUE; + + /* Initialize the nonpaged pool */ + MiBuildNonPagedPool(); + + /* Initialize system PTE handling */ + MiBuildSystemPteSpace(); + + /* Build the physical memory block */ + MiBuildPhysicalMemoryBlock(LoaderBlock); + + /* Size up paged pool and build the shadow system page directory */ + //MiBuildPagedPool(); + + // This is the old stuff: + MmPagedPoolBase = (PVOID)((PCHAR)MmPagedPoolEnd + 1); + MmPagedPoolSize = MM_PAGED_POOL_SIZE; + ASSERT((PCHAR)MmPagedPoolBase + MmPagedPoolSize < (PCHAR)MmNonPagedSystemStart); + + + HalInitializeBios(0, LoaderBlock); + } + + return STATUS_SUCCESS; +} + +VOID +FASTCALL +MiSyncARM3WithROS(IN PVOID AddressStart, + IN PVOID AddressEnd) +{ + +} + +NTSTATUS +NTAPI +MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} diff --git a/reactos/ntoskrnl/mm/amd64/page.c b/reactos/ntoskrnl/mm/amd64/page.c new file mode 100644 index 00000000000..d9830b409e8 --- /dev/null +++ b/reactos/ntoskrnl/mm/amd64/page.c @@ -0,0 +1,534 @@ +/* + * COPYRIGHT: GPL, See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/amd64/page.c + * PURPOSE: Low level memory managment manipulation + * + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ***************************************************************/ + +#include +#define NDEBUG +#include + +#undef InterlockedExchangePte +#define InterlockedExchangePte(pte1, pte2) \ + InterlockedExchange64((LONG64*)&pte1->u.Long, pte2.u.Long) + +#define PAGE_EXECUTE_ANY (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY) +#define PAGE_WRITE_ANY (PAGE_EXECUTE_READWRITE|PAGE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY) +#define PAGE_WRITECOPY_ANY (PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY) + +extern MMPTE HyperTemplatePte; + +/* GLOBALS *****************************************************************/ + + +/* PRIVATE FUNCTIONS *******************************************************/ + +BOOLEAN +FORCEINLINE +MiIsHyperspaceAddress(PVOID Address) +{ + return ((ULONG64)Address >= HYPER_SPACE && + (ULONG64)Address <= HYPER_SPACE_END); +} + +VOID +MiFlushTlb(PMMPTE Pte, PVOID Address) +{ + if (MiIsHyperspaceAddress(Pte)) + { + MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); + } + else + { + __invlpg(Address); + } +} + +static +PMMPTE +MiGetPteForProcess( + PEPROCESS Process, + PVOID Address, + BOOLEAN Create) +{ + MMPTE TmplPte, *Pte; + + /* Check if we need hypersapce mapping */ + if (Address < MmSystemRangeStart && + Process && Process != PsGetCurrentProcess()) + { + UNIMPLEMENTED; + return NULL; + } + else if (Create) + { + TmplPte.u.Long = 0; + TmplPte.u.Flush.Valid = 1; + TmplPte.u.Flush.Write = 1; + + /* Get the PXE */ + Pte = MiAddressToPxe(Address); + if (!Pte->u.Hard.Valid) + { +// TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE); + InterlockedExchangePte(Pte, TmplPte); + } + + /* Get the PPE */ + Pte = MiAddressToPpe(Address); + if (!Pte->u.Hard.Valid) + { +// TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE); + InterlockedExchangePte(Pte, TmplPte); + } + + /* Get the PDE */ + Pte = MiAddressToPde(Address); + if (!Pte->u.Hard.Valid) + { +// TmplPte.u.Hard.PageFrameNumber = MiAllocPage(TRUE); + InterlockedExchangePte(Pte, TmplPte); + } + } + else + { + /* Get the PXE */ + Pte = MiAddressToPxe(Address); + if (!Pte->u.Hard.Valid) + return NULL; + + /* Get the PPE */ + Pte = MiAddressToPpe(Address); + if (!Pte->u.Hard.Valid) + return NULL; + + /* Get the PDE */ + Pte = MiAddressToPde(Address); + if (!Pte->u.Hard.Valid) + return NULL; + } + + return MiAddressToPte(Address); +} + +static +ULONG64 +MiGetPteValueForProcess( + PEPROCESS Process, + PVOID Address) +{ + PMMPTE Pte; + ULONG64 PteValue; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + PteValue = Pte ? Pte->u.Long : 0; + + if (MiIsHyperspaceAddress(Pte)) + MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); + + return PteValue; +} + +ULONG +NTAPI +MiGetPteProtection(MMPTE Pte) +{ + ULONG Protect; + + if (!Pte.u.Flush.Valid) + { + Protect = PAGE_NOACCESS; + } + else if (Pte.u.Flush.NoExecute) + { + if (Pte.u.Flush.CopyOnWrite) + Protect = PAGE_WRITECOPY; + else if (Pte.u.Flush.Write) + Protect = PAGE_READWRITE; + else + Protect = PAGE_READONLY; + } + else + { + if (Pte.u.Flush.CopyOnWrite) + Protect = PAGE_EXECUTE_WRITECOPY; + else if (Pte.u.Flush.Write) + Protect = PAGE_EXECUTE_READWRITE; + else + Protect = PAGE_EXECUTE_READ; + } + + if (Pte.u.Flush.CacheDisable) + Protect |= PAGE_NOCACHE; + + if (Pte.u.Flush.WriteThrough) + Protect |= PAGE_WRITETHROUGH; + + // PAGE_GUARD ? + return Protect; +} + +VOID +NTAPI +MiSetPteProtection(PMMPTE Pte, ULONG Protection) +{ + Pte->u.Flush.CopyOnWrite = (Protection & PAGE_WRITECOPY_ANY) ? 1 : 0; + Pte->u.Flush.Write = (Protection & PAGE_WRITE_ANY) ? 1 : 0; + Pte->u.Flush.CacheDisable = (Protection & PAGE_NOCACHE) ? 1 : 0; + Pte->u.Flush.WriteThrough = (Protection & PAGE_WRITETHROUGH) ? 1 : 0; + + // FIXME: This doesn't work. Why? +// Pte->u.Flush.NoExecute = (Protection & PAGE_EXECUTE_ANY) ? 0 : 1; +} + +/* FUNCTIONS ***************************************************************/ + +PFN_NUMBER +NTAPI +MmGetPfnForProcess(PEPROCESS Process, + PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid ? Pte.u.Hard.PageFrameNumber : 0; +} + +PHYSICAL_ADDRESS +NTAPI +MmGetPhysicalAddress(PVOID Address) +{ + PHYSICAL_ADDRESS p; + MMPTE Pte; + + Pte.u.Long = MiGetPteValueForProcess(NULL, Address); + if (Pte.u.Hard.Valid) + { + p.QuadPart = Pte.u.Hard.PageFrameNumber * PAGE_SIZE; + p.u.LowPart |= (ULONG_PTR)Address & (PAGE_SIZE - 1); + } + else + { + p.QuadPart = 0; + } + + return p; +} + +BOOLEAN +NTAPI +MmIsPagePresent(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid; +} + +BOOLEAN +NTAPI +MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid && Pte.u.Soft.Transition; +} + +BOOLEAN +NTAPI +MmIsDirtyPage(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + return Pte.u.Hard.Valid && Pte.u.Hard.Dirty; +} + +ULONG +NTAPI +MmGetPageProtect(PEPROCESS Process, PVOID Address) +{ + MMPTE Pte; + + Pte.u.Long = MiGetPteValueForProcess(Process, Address); + + return MiGetPteProtection(Pte); +} + +VOID +NTAPI +MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) +{ + PMMPTE Pte; + MMPTE NewPte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + ASSERT(Pte != NULL); + + NewPte = *Pte; + + MiSetPteProtection(&NewPte, flProtect); + + InterlockedExchangePte(Pte, NewPte); + + MiFlushTlb(Pte, Address); +} + +VOID +NTAPI +MmSetCleanPage(PEPROCESS Process, PVOID Address) +{ + PMMPTE Pte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + if (!Pte) + { + KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0); + } + + /* Ckear the dirty bit */ + if (InterlockedBitTestAndReset64((PVOID)Pte, 6)) + { + if (!MiIsHyperspaceAddress(Pte)) + __invlpg(Address); + } + + MiFlushTlb(Pte, Address); +} + +VOID +NTAPI +MmSetDirtyPage(PEPROCESS Process, PVOID Address) +{ + PMMPTE Pte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + if (!Pte) + { + KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0); + } + + /* Ckear the dirty bit */ + if (InterlockedBitTestAndSet64((PVOID)Pte, 6)) + { + if (!MiIsHyperspaceAddress(Pte)) + __invlpg(Address); + } + + MiFlushTlb(Pte, Address); +} + + +NTSTATUS +NTAPI +Mmi386ReleaseMmInfo(PEPROCESS Process) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + +VOID +NTAPI +MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +MmRawDeleteVirtualMapping(PVOID Address) +{ + UNIMPLEMENTED; +} + +VOID +NTAPI +MmDeleteVirtualMapping( + PEPROCESS Process, + PVOID Address, + BOOLEAN FreePage, + BOOLEAN* WasDirty, + PPFN_NUMBER Page) +{ + PFN_NUMBER Pfn; + PMMPTE Pte; + MMPTE OldPte; + + Pte = MiGetPteForProcess(Process, Address, FALSE); + + if (Pte) + { + /* Atomically set the entry to zero and get the old value. */ + OldPte.u.Long = InterlockedExchange64((LONG64*)&Pte->u.Long, 0); + + if (OldPte.u.Hard.Valid) + { + Pfn = OldPte.u.Hard.PageFrameNumber; + + if (FreePage) + MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); + } + else + Pfn = 0; + } + else + { + OldPte.u.Long = 0; + Pfn = 0; + } + + /* Return information to the caller */ + if (WasDirty) + *WasDirty = OldPte.u.Hard.Dirty;; + + if (Page) + *Page = Pfn; + + MiFlushTlb(Pte, Address); +} + +VOID +NTAPI +MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, + SWAPENTRY* SwapEntry) +{ + UNIMPLEMENTED; +} + + +VOID +NTAPI +MmEnableVirtualMapping(PEPROCESS Process, PVOID Address) +{ + UNIMPLEMENTED; +} + + +NTSTATUS +NTAPI +MmCreatePageFileMapping(PEPROCESS Process, + PVOID Address, + SWAPENTRY SwapEntry) +{ + UNIMPLEMENTED; + return STATUS_UNSUCCESSFUL; +} + + +NTSTATUS +NTAPI +MmCreateVirtualMappingUnsafe( + PEPROCESS Process, + PVOID Address, + ULONG PageProtection, + PPFN_NUMBER Pages, + ULONG PageCount) +{ + ULONG i; + MMPTE TmplPte, *Pte; + + /* Check if the range is valid */ + if ((Process == NULL && Address < MmSystemRangeStart) || + (Process != NULL && Address > MmHighestUserAddress)) + { + DPRINT1("Address 0x%p is invalid for process %p\n", Address, Process); + ASSERT(FALSE); + } + + TmplPte.u.Long = 0; + TmplPte.u.Hard.Valid = 1; + MiSetPteProtection(&TmplPte, PageProtection); + +//__debugbreak(); + + for (i = 0; i < PageCount; i++) + { + TmplPte.u.Hard.PageFrameNumber = Pages[i]; + + Pte = MiGetPteForProcess(Process, Address, TRUE); + +DPRINT1("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n", + Address, TmplPte.u.Long, Pte); + + if (InterlockedExchangePte(Pte, TmplPte)) + { + KeInvalidateTlbEntry(Address); + } + + if (MiIsHyperspaceAddress(Pte)) + MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); + + Address = (PVOID)((ULONG64)Address + PAGE_SIZE); + } + + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +MmCreateVirtualMapping(PEPROCESS Process, + PVOID Address, + ULONG Protect, + PPFN_NUMBER Pages, + ULONG PageCount) +{ + ULONG i; + + for (i = 0; i < PageCount; i++) + { + if (!MmIsPageInUse(Pages[i])) + { + DPRINT1("Page %x not in use\n", Pages[i]); + KeBugCheck(MEMORY_MANAGEMENT); + } + } + + return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount); +} + +NTSTATUS +NTAPI +MmInitializeHandBuiltProcess(IN PEPROCESS Process, + IN PULONG_PTR DirectoryTableBase) +{ + /* Share the directory base with the idle process */ + DirectoryTableBase[0] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]; + DirectoryTableBase[1] = PsGetCurrentProcess()->Pcb.DirectoryTableBase[1]; + + /* Initialize the Addresss Space */ + KeInitializeGuardedMutex(&Process->AddressCreationLock); + Process->Vm.WorkingSetExpansionLinks.Flink = NULL; + ASSERT(Process->VadRoot.NumberGenericTableElements == 0); + Process->VadRoot.BalancedRoot.u1.Parent = &Process->VadRoot.BalancedRoot; + + /* The process now has an address space */ + Process->HasAddressSpace = TRUE; + return STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +MmCreateProcessAddressSpace(IN ULONG MinWs, + IN PEPROCESS Process, + IN PULONG_PTR DirectoryTableBase) +{ + UNIMPLEMENTED; + return 0; +} + +BOOLEAN +NTAPI +_MmIsAddressValid(IN PVOID VirtualAddress) +{ + /* Check all four page table levels */ + return (MiAddressToPxe(VirtualAddress)->u.Hard.Valid != 0 && + MiAddressToPpe(VirtualAddress)->u.Hard.Valid != 0 && + MiAddressToPde(VirtualAddress)->u.Hard.Valid != 0 && + MiAddressToPte(VirtualAddress)->u.Hard.Valid != 0); +} + + +/* EOF */ diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index 03ce565623a..6b7cc84eca8 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -84,6 +84,22 @@ ctxhelp.S + + + boot.S + context.c + cpu.c + ctxswitch.S + except.c + interrupt.c + irql.c + kiinit.c + spinlock.c + stubs.c + thrdini.c + trap.S + + apc.c balmgr.c bug.c @@ -93,7 +109,9 @@ dpc.c eventobj.c except.c - freeldr.c + + freeldr.c + freeze.c gate.c gmutex.c @@ -125,6 +143,11 @@ cmhardwr.c + + + cmhardwr.c + + cmhardwr.c @@ -178,6 +201,11 @@ ioport.S + + + fastinterlck.c + + atom.c callback.c dbgctrl.c @@ -299,6 +327,17 @@ + + + + + i386-dis.c + kdb_help.S + kdb.c + + + + kdb.c kdb_cli.c @@ -321,6 +360,12 @@ kdbg.c + + + kd.c + kdmemsup.c + + kdinit.c kdio.c kdmain.c @@ -379,6 +424,12 @@ page.c + + + init.c + page.c + + @@ -462,6 +513,11 @@ psctx.c + + + psctx.c + + debug.c job.c kill.c diff --git a/reactos/ntoskrnl/ps/amd64/psctx.c b/reactos/ntoskrnl/ps/amd64/psctx.c new file mode 100644 index 00000000000..57ed4daa639 --- /dev/null +++ b/reactos/ntoskrnl/ps/amd64/psctx.c @@ -0,0 +1,95 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ps/amd64/pxctx.c + * PURPOSE: Process Manager: Set/Get Context for i386 + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + * Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS ******************************************************************/ + +VOID +NTAPI +PspGetContext(IN PKTRAP_FRAME TrapFrame, + IN PVOID NonVolatileContext, + IN OUT PCONTEXT Context) +{ + PAGED_CODE(); + + /* Convert the trap frame to a context */ + KeTrapFrameToContext(TrapFrame, NULL, Context); +} + +VOID +NTAPI +PspSetContext(OUT PKTRAP_FRAME TrapFrame, + OUT PVOID NonVolatileContext, + IN PCONTEXT Context, + IN KPROCESSOR_MODE Mode) +{ + PAGED_CODE(); + + /* Convert the context to a trap frame structure */ + KeContextToTrapFrame(Context, NULL, TrapFrame, Context->ContextFlags, Mode); +} + +VOID +NTAPI +PspGetOrSetContextKernelRoutine(IN PKAPC Apc, + IN OUT PKNORMAL_ROUTINE* NormalRoutine, + IN OUT PVOID* NormalContext, + IN OUT PVOID* SystemArgument1, + IN OUT PVOID* SystemArgument2) +{ + PGET_SET_CTX_CONTEXT GetSetContext; + PKEVENT Event; + PCONTEXT Context; + PKTHREAD Thread; + KPROCESSOR_MODE Mode; + PKTRAP_FRAME TrapFrame = NULL; + PAGED_CODE(); + + /* Get the Context Structure */ + GetSetContext = CONTAINING_RECORD(Apc, GET_SET_CTX_CONTEXT, Apc); + Context = &GetSetContext->Context; + Event = &GetSetContext->Event; + Mode = GetSetContext->Mode; + Thread = Apc->SystemArgument2; + + /* If this is a kernel-mode request, grab the saved trap frame */ + if (Mode == KernelMode) TrapFrame = Thread->TrapFrame; + + /* If we don't have one, grab it from the stack */ + if (!TrapFrame) + { + DPRINT1("FIXME!!!!\n"); + /* Trap frame is right under our initial stack */ +// TrapFrame = (PKTRAP_FRAME)((ULONG_PTR)Thread->InitialStack - +// ROUND_UP(sizeof(KTRAP_FRAME), KTRAP_FRAME_ALIGN) - +// sizeof(FX_SAVE_AREA)); + } + + /* Check if it's a set or get */ + if (Apc->SystemArgument1) + { + /* Get the Context */ + PspSetContext(TrapFrame, NULL, Context, Mode); + } + else + { + /* Set the Context */ + PspGetContext(TrapFrame, NULL, Context); + } + + /* Notify the Native API that we are done */ + KeSetEvent(Event, IO_NO_INCREMENT, FALSE); +} + +/* EOF */