%include "SYS.macros" %include "FormattedIO.macros" ;; maybe useful macros... %macro printit2 2 SYS_WRITE 1,%1_name,%2 SYS_WRITE 1,space_equal_space,3 hex8out %1_reg,outstring SYS_WRITE 1,outstring,16 SYS_WRITE 1,eoln,1 %endmacro %macro printit 2 SYS_WRITE 1,%1_name,%2 SYS_WRITE 1,space_equal_space,3 hex8out %1_reg_offset+allregisters,outstring SYS_WRITE 1,outstring,16 SYS_WRITE 1,eoln,1 %endmacro ;; So the idea here is that we have the ability to save as much ;; cpu state as is possible. ;; I am going to allow for an arbitrary number of such savings areas, ;; although two is all that I seem to need for a simple implementation ;; Unfortunately, I think we will have to have both a 32bit version ;; and a 64bit version. ;;; 64bits! ;; Regular registers (MOV or PUSH) ;; ;; RAX ;; RBX ;; RCX ;; RDX ;; RBP ;; RSI ;; RDI ;; RSP ;; R8 ;; R9 ;; R10 ;; R11 ;; R12 ;; R13 ;; R14 ;; R15 ;; ;; Instruction pointer ;; ;; RIP ;; ;; Control and status registers (Can "PUSHFQ") ;; ;; RFLAGS ;; ;; Floating point / MMX (use FP since it gets all 80 of the bits; MMX is only lower 64) (FSAVE, FXSAVE, XSAVE) ;; ;; FPR0 / MMX0 ;; FPR1 / MMX1 ;; FPR2 / MMX2 ;; FPR3 / MMX3 ;; FPR4 / MMX4 ;; FPR5 / MMX5 ;; FPR6 / MMX6 ;; FPR7 / MMX7 ;; ;; XMM registers (FXSAVE, XSAVE) ;; ;; XMM0 ;; XMM1 ;; XMM2 ;; XMM3 ;; XMM4 ;; XMM5 ;; XMM6 ;; XMM7 ;; XMM8 ;; XMM9 ;; XMM10 ;; XMM11 ;; XMM12 ;; XMM13 ;; XMM14 ;; XMM15 ;; ;; AVX registers (XSAVE) ;; ;; YMM0 ;; YMM1 ;; YMM2 ;; YMM3 ;; YMM4 ;; YMM5 ;; YMM6 ;; YMM7 ;; YMM8 ;; YMM9 ;; YMM10 ;; YMM11 ;; YMM12 ;; YMM13 ;; YMM14 ;; YMM15 ;; ;; Segment registers (??cannot get to legacy CS, DS, ES, SS??) (Can PUSH these onto the stack) ;; ;; CS ;; DS ;; ES ;; SS ;; FS ;; GS ;; ;; Control registers (regular MOV to/from register) ;; ;; CR0 ;; CR1 (actually does not exist/inaccessible, read from should cause error, at least according to later pages in the 64-ia-32 manual) ;; CR2 ;; CR3 ;; CR4 ;; CR5 (actually does not exist, read from should cause error) ;; CR6 (actually does not exist, read from should cause error) ;; CR7 (actually does not exist, read from should cause error) ;; CR8 ;; ;; Extended control registers (XGETBV instruction; reads XCRn from ECX, writes to EDX:EAX ---> but XGETBV is not present on all processors...) ;; ;; XCR0 ;; ;; Memory management registers (I doubt that these are available without privilege) ;; ;; Debug registers (regular MOV to/from register, but require privilege; also DR4/DR5/DR6/DR7 are squirrelly) ;; ;; DR0 ;; DR1 ;; DR2 ;; DR3 ;; DR4 ;; DR5 ;; DR6 ;; DR7 ;; ;; Virtualization registers (?) ;; ;; Model specific registers (MSR) ("RDMSR" instruction, but requires privilege; also, the SWAPGS instruction accesses an MSR) ;; ;; Performance registers ("RDPMC" instruction) ;; ;; x87 registers? ;; ;; ST0 / MM0 ;; ST1 / MM1 ;; ST2 / MM2 ;; ST3 / MM3 ;; ST4 / MM4 ;; ST5 / MM5 ;; ST6 / MM6 ;; ST7 / MM7 ;; ;; There is a time stamp counter (TSC), but I don't think it's worth checking... ;; ;; Global descriptor table register (special SGDT instruction, can put data anywhere) ;; ;; Interrupt descriptor table register (special SIDT, can put data anywhere) ;; ;; Local descriptor table register (special SLDT register, requires privilege, can put data anywhere) ;; ;; MXCSR register (STMXCSR, stores to a four byte memory location) ;; ;; TR Task register (STR, requires privilege, stores to either memory or register) ;; ;; MSW register ("SMSW") ;; ;; ARPL ? ;; ;; VERR ? VERW ? ;; ;; LAR ? LSL ? ;; ;; ;;; XSAVE considerations ;;; ;;; After plowing through Chapter 13 of the most recent Intel combined architecture manuals, XSAVE is a real ;;; nuisance. There seem to be so many fiddly flags that have to be set to make this XSAVE do anything. ;;; ;;; This paragraph, from page 298, is bizarrely at the end of the section. It seems to be very important, and thus ;;; should have been earlier? ;;; ;; "As will be explained in Section 13.3, the XSAVE feature set is enabled only if CR4.OSXSAVE[bit 18] = 1. If ;; CR4.OSXSAVE = 0, the processor treats XSAVE-enabled state components and features as if all bits in XCR0 were ;; clear; the state components cannot be modified and the features’ instructions cannot be executed." ;;; First question: what the heck is CR4? Clearly, it's control register 4, but how do we access this register? ;;; ;;; Answer: As CR4. "MOV RAX,CR4" is a legitimate instruction. ;;; INTERESTING PAGE --> http://lists.freebsd.org/pipermail/freebsd-amd64/2011-March/013744.html ;;; Some rough order: ;;; ;;; ;;; RIP --> ;;; RSP --> ;;; RAX --> ;;; section .data makehextable ;;; our strings space: db " " equal: db "=" space_equal_space: db 9,"= " eoln: db 10 hex_prefix: db "0x" yes_eoln: db "yes",10 no_eoln: db "no",10 rip_name: db "rip" rsp_name: db "rsp" rflags_name: db "rflags" rsi_name: db "rsi" rdi_name: db "rdi" rax_name: db "rax" rbx_name: db "rbx" rcx_name: db "rcx" rdx_name: db "rdx" r8_name: db "r8" r9_name: db "r9" r10_name: db "r10" r11_name: db "r11" r12_name: db "r12" r13_name: db "r13" r14_name: db "r14" r15_name: db "r15" cs_name: db "cs" ds_name: db "ds" ss_name: db "ss" es_name: db "es" fs_name: db "fs" gs_name: db "gs" cr0_name: db "cr0" cr1_name: db "cr1" cr2_name: db "cr2" cr3_name: db "cr3" cr4_name: db "cr4" cr5_name: db "cr5" cr6_name: db "cr6" cr7_name: db "cr7" cr8_name: db "cr8" xcr0_name: db "xcr0" xsave_name: db "xsave" ;;; ;;; CPUID with EAX set to 0x0 information ;;; ;;; ;;; Essentially, you get two things: 1) what's the maximum value that you can set in EAX for other calls to CPUID, returned in EAX ;;; 2) an identification string in EBX, ECX, and EDX processor_name: db "Processor identifier (from CPUID with EAX set to 0): " processor_name_len equ $ - processor_name max_cpuid: db 0 msg_max_cpuid: db "Maximum parameter in EAX for CPUID normal function: " msg_max_cpuid_len equ $ - msg_max_cpuid msg_max_cpuid_data: db " " ; two bytes for the output of the previous ;;; ;;; ;;; CPUID with EAX set to 0x1 ;;; ;;; ;;; ;;; EAX information for CPUID when EAX set to 0x1 model_family_stepping: db 0,0,0,0 msg_model_family_stepping: db "Modem / Family / Stepping: " msg_model_family_stepping_len equ $ - msg_model_family_stepping ;;; EBX information for CPUID when EAX set to 0x1 brand_index: db 0 ; low byte CLFLUSH_instruction_cache_line_size: db 0 ; next byte up logical_processor_count: db 0 ; next byte up local_apic_id: db 0 ; highest byte msg_brand_index: db "Brand index: " msg_brand_index_len equ $ - msg_brand_index msg_CLFLUSH_instruction_cache_line_size: db "CLFLUSH cache line size: " msg_CLFLUSH_instruction_cache_line_size_len equ $ - msg_CLFLUSH_instruction_cache_line_size msg_logical_processor_count: db "Logical processor count: " msg_logical_processor_count_len equ $ - msg_logical_processor_count msg_local_apic_id: db "Local APIC id: " msg_local_apic_id_len equ $ - msg_local_apic_id ;;; ECX information for CPUID when EAX set to 0x1 msg_cpuid_eax_1_ecx_output: db "***",10,"*** CPUID FUNCTION EAX set to 1 ==> ECX OUTPUT",10,"***",10 msg_cpuid_eax_1_ecx_output_len equ $ - msg_cpuid_eax_1_ecx_output %assign SSE3_VALUE 0 msg_SSE3: db "SSE3",9 msg_SSE3_len equ $ - msg_SSE3 %assign PCLMULQDQ_VALUE 1 msg_PCLMULQDQ: db "PCLMULQDQ" msg_PCLMULQDQ_len equ $ - msg_PCLMULQDQ %assign DTES64_VALUE 2 msg_DTES64: db "DTES64",9 msg_DTES64_len equ $ - msg_DTES64 %assign MONITOR_MWAIT_VALUE 3 msg_MONITOR_MWAIT: db "MONITOR_MWAIT" msg_MONITOR_MWAIT_len equ $ - msg_MONITOR_MWAIT %assign DS_CPL_VALUE 4 msg_DS_CPL: db "DS_CPL",9 msg_DS_CPL_len equ $ - msg_DS_CPL %assign VMX_VALUE 5 msg_VMX: db "VMX",9 msg_VMX_len equ $ - msg_VMX %assign SMX_VALUE 6 msg_SMX: db "SMX",9 msg_SMX_len equ $ - msg_SMX %assign EIST_VALUE 7 msg_EIST: db "EIST",9 msg_EIST_len equ $ - msg_EIST %assign TM2_VALUE 8 msg_TM2: db "TM2",9 msg_TM2_len equ $ - msg_TM2 %assign SSSE3_VALUE 9 msg_SSSE3: db "SSSE3",9 msg_SSSE3_len equ $ - msg_SSSE3 %assign CNXT_ID_VALUE 10 msg_CNXT_ID: db "CNXT_ID",9 msg_CNXT_ID_len equ $ - msg_CNXT_ID %assign SDBG_VALUE 11 msg_SDBG: db "SDBG",9 msg_SDBG_len equ $ - msg_SDBG %assign FMA_VALUE 12 msg_FMA: db "FMA",9 msg_FMA_len equ $ - msg_FMA %assign CMPXCHG16B_VALUE 13 msg_CMPXCHG16B: db "CMPXCHG16B" msg_CMPXCHG16B_len equ $ - msg_CMPXCHG16B %assign xTPR_VALUE 14 msg_xTPR: db "xTPR",9 msg_xTPR_len equ $ - msg_xTPR %assign PDCM_VALUE 15 msg_PDCM: db "PDCM",9 msg_PDCM_len equ $ - msg_PDCM %assign PCID_VALUE 17 msg_PCID: db "PCID",9 msg_PCID_len equ $ - msg_PCID %assign DCA_VALUE 18 msg_DCA: db "DCA",9 msg_DCA_len equ $ - msg_DCA %assign SSE4_1_VALUE 19 msg_SSE4_1: db "SSE4_1",9 msg_SSE4_1_len equ $ - msg_SSE4_1 %assign SSE4_2_VALUE 20 msg_SSE4_2: db "SSE4_2",9 msg_SSE4_2_len equ $ - msg_SSE4_2 %assign x2APIC_VALUE 21 msg_x2APIC: db "x2APIC",9 msg_x2APIC_len equ $ - msg_x2APIC %assign MOVBE_VALUE 22 msg_MOVBE: db "MOVBE",9 msg_MOVBE_len equ $ - msg_MOVBE %assign POPCNT_VALUE 23 msg_POPCNT: db "POPCNT",9 msg_POPCNT_len equ $ - msg_POPCNT %assign TSC_Deadline_VALUE 24 msg_TSC_Deadline: db "TSC_Deadline" msg_TSC_Deadline_len equ $ - msg_TSC_Deadline %assign AESNI_VALUE 25 msg_AESNI: db "AESNI",9 msg_AESNI_len equ $ - msg_AESNI %assign XSAVE_VALUE 26 msg_XSAVE: db "XSAVE",9 msg_XSAVE_len equ $ - msg_XSAVE %assign OSXSAVE_VALUE 27 msg_OSXSAVE: db "OSXSAVE",9 msg_OSXSAVE_len equ $ - msg_OSXSAVE %assign AVX_VALUE 28 msg_AVX: db "AVX",9 msg_AVX_len equ $ - msg_AVX %assign F16C_VALUE 29 msg_F16C: db "F16C",9 msg_F16C_len equ $ - msg_F16C %assign RDRAND_VALUE 30 msg_RDRAND: db "RDRAND",9 msg_RDRAND_len equ $ - msg_RDRAND %assign ALWAYS_ZERO_VALUE 31 msg_ALWAYS_ZERO: db "ALWAYS_ZERO" msg_ALWAYS_ZERO_len equ $ - msg_ALWAYS_ZERO ;;; ;;; EDX information for CPUID when EAX = 1 ;;; msg_cpuid_eax_1_edx_output: db "***",10,"*** CPUID FUNCTION EAX set to 1 ==> EDX OUTPUT",10,"***",10 msg_cpuid_eax_1_edx_output_len equ $ - msg_cpuid_eax_1_edx_output %assign FPU_VALUE 0 msg_FPU : db "FPU",9 msg_FPU_len equ $ - msg_FPU %assign VME_VALUE 1 msg_VME : db "VME",9 msg_VME_len equ $ - msg_VME %assign DE_VALUE 2 msg_DE : db "DE",9 msg_DE_len equ $ - msg_DE %assign PSE_VALUE 3 msg_PSE : db "PSE",9 msg_PSE_len equ $ - msg_PSE %assign TSC_VALUE 4 msg_TSC : db "TSC",9 msg_TSC_len equ $ - msg_TSC %assign MSR_VALUE 5 msg_MSR : db "MSR",9 msg_MSR_len equ $ - msg_MSR %assign PAE_VALUE 6 msg_PAE : db "PAE",9 msg_PAE_len equ $ - msg_PAE %assign MCE_VALUE 7 msg_MCE : db "MCE",9 msg_MCE_len equ $ - msg_MCE %assign CX8_VALUE 8 msg_CX8 : db "CX8",9 msg_CX8_len equ $ - msg_CX8 %assign APIC_VALUE 9 msg_APIC : db "APIC",9 msg_APIC_len equ $ - msg_APIC %assign SEP_VALUE 11 msg_SEP : db "SEP",9 msg_SEP_len equ $ - msg_SEP %assign MTRR_VALUE 12 msg_MTRR : db "MTRR",9 msg_MTRR_len equ $ - msg_MTRR %assign PGE_VALUE 13 msg_PGE: db "PGE",9 msg_PGE_len equ $ - msg_PGE %assign MCA_VALUE 14 msg_MCA db "MCA",9 msg_MCA_len equ $ - msg_MCA %assign CMOV_VALUE 15 msg_CMOV : db "CMOV",9 msg_CMOV_len equ $ - msg_CMOV %assign PAT_VALUE 16 msg_PAT : db "PAT",9 msg_PAT_len equ $ - msg_PAT %assign PSE_36_VALUE 17 msg_PSE_36 : db "PSE-36",9 msg_PSE_36_len equ $ - msg_PSE_36 %assign PSN_VALUE 18 msg_PSN: db "PSN",9 msg_PSN_len equ $ - msg_PSN %assign CFLSH_VALUE 19 msg_CFLSH: db "CFLSH",9 msg_CFLSH_len equ $ - msg_CFLSH %assign DS_VALUE 21 msg_DS : db "DS",9 msg_DS_len equ $ - msg_DS %assign ACPI_VALUE 22 msg_ACPI : db "ACPI",9 msg_ACPI_len equ $ - msg_ACPI %assign MMX_VALUE 23 msg_MMX : db "MMX",9 msg_MMX_len equ $ - msg_MMX %assign FXSR_VALUE 24 msg_FXSR : db "FXSR",9 msg_FXSR_len equ $ - msg_FXSR %assign SSE_VALUE 25 msg_SSE : db "SSE",9 msg_SSE_len equ $ - msg_SSE %assign SSE2_VALUE 26 msg_SSE2 : db "SSE2",9 msg_SSE2_len equ $ - msg_SSE2 %assign SS_VALUE 27 msg_SS : db "SS",9 msg_SS_len equ $ - msg_SS %assign HTT_VALUE 28 msg_HTT : db "HTT",9 msg_HTT_len equ $ - msg_HTT %assign TM_VALUE 29 msg_TM : db "TM",9 msg_TM_len equ $ - msg_TM %assign PBE_VALUE 31 msg_PBE : db "PBE",9 msg_PBE_len equ $ - msg_PBE ;;; ;;; ;;; CPUID with EAX set to 0x2 ;;; ;;; ;;; ;; Looking at the Intel documentation, this seems to be potentially *STATEFUL!* ;; To quote page 3-174: ;; "When CPUID executes with EAX set to 2, the processor returns information about the processor’s internal TLBs, ;; cache and prefetch hardware in the EAX, EBX, ECX, and EDX registers. The information is reported in encoded form ;; and fall into the following categories: ;; ;; • The least-significant byte in register EAX (register AL) indicates the number of times the CPUID instruction ;; must be executed with an input value of 2 to get a complete description of the processor’s TLB/Cache/Prefetch ;; hardware. The Intel Xeon processor 7400 series will return a 1." ;; If this is the case, then could this be useful for some type of side channel communication? At the least, if ;; a processor requires N > 0 states to cycle through this, then couldn't you detect N+1 states? ;; ;; Interestingly, the AMD documentation that I have seems to show that this is just reserved, not implemented. ;; ;;; ;;; ;;; CPUID with EAX set to 0x3 ;;; ;;; ;; This was used for 96 bit processor ids, but no longer ;;; ;;; ;;; CPUID with EAX set to 0x4 ;;; ;;; ;;; ;; Apparently this is for showing cache features/state in Intel, but it is shown as just reserved in AMD ;;; ;;; ;;; CPUID with EAX set to 0x5 ;;; ;;; ;;; ;; MONITOR/MWAIT information mon_line_size_min: db 0,0 mon_line_size_max: db 0,0 msg_mon_line_size_min: db "Smallest monitor-line size in bytes: " msg_mon_line_size_min_len equ $ - msg_mon_line_size_min msg_mon_line_size_max: db "Largest monitor-line size in bytes: " msg_mon_line_size_max_len equ $ - msg_mon_line_size_max eax_05_ecx_bit_0: db "Enumeration of MONITOR/MWAIT extensions is supported = " eax_05_ecx_bit_0_len equ $ - eax_05_ecx_bit_0 eax_05_ecx_bit_1: db "Supports treating interrupts as break-event for MWAIT, even when interrupts disabled = " eax_05_ecx_bit_1_len equ $ - eax_05_ecx_bit_0 ;;; ;;; CPUID with EAX set to 0x80000000 information ;;; max_cpuid_extended: db 0 msg_max_cpuid_extended: db "Maxiumum parameter in EAX for CPUID extended function: " msg_max_cpuid_extended_len equ $ - msg_max_cpuid_extended msg_max_cpuid_extended_data: db " " ;;; ;;; CPUID with EAX set to 0x80000001 information ;;; ;; EAX ? ;; EBX is reserved ;; Flags in ECX %assign LAHF_SAHF_VALUE 0 msg_LAHF_SAHF: db "LAHF/SAHF available" msg_LAHF_SAHF_len equ $ - msg_LAHF_SAHF %assign LZCNT_VALUE 4 msg_LZCNT: db "LZCNT",9 msg_LZCNT_len equ $ - msg_LZCNT %assign PREFETCHW_VALUE 8 msg_PREFETCHW: db "PREFETCHW" msg_PREFETCHW_len equ $ - msg_PREFETCHW ;; Flags in EDX %assign SYSCALL_SYSRET_VALUE 11 msg_SYSCALL_SYSRET: db "SYSCALL_SYSRET" msg_SYSCALL_SYSRET_len equ $ - msg_SYSCALL_SYSRET %assign EXECUTE_DISABLE 20 msg_EXECUTE_DISABLE: db "EXECUTE DISABLE" msg_EXECUTE_DISABLE_len equ $ - msg_EXECUTE_DISABLE %assign GIGABYTE_PAGE 26 msg_GIGABYTE_PAGE: db "GIGABYTE_PAGE" msg_GIGABYTE_PAGE_len equ $ - msg_GIGABYTE_PAGE %assign INTEL64 29 msg_INTEL64: db "Intel 64 arch available" msg_INTEL64_len equ $ - msg_INTEL64 ;;; ;;; CPUID with EAX set to 0x80000002 ;;; msg_processor_brand_string: db "Process Brand String: " msg_processor_brand_string_len equ $ - msg_processor_brand_string process_brand_string: times 12 db 0 ;;; ;;; Miscellaneous messages ;;; msg_have_xcr0: db "Found XCR0 register, retrieving values...",13 msg_have_xcr0_len equ $ - msg_have_xcr0 ;;; ;;; ;;; Data! ;;; ;;; allregisters: ;;; ;;; Registers that are related to the running of the ;;; current process ;;; rip_reg_offset equ $ - allregisters rip_reg: dq 0 rsp_reg_offset equ $ - allregisters rsp_reg: dq 0 rflags_reg_offset equ $ - allregisters rflags_reg: dq 0 ;;; ;;; Index registers ;;; rsi_reg_offset equ $ - allregisters rsi_reg: dq 0 rdi_reg_offset equ $ - allregisters rdi_reg: dq 0 ;;; ;;; General purpose registers ;;; rax_reg_offset equ $ - allregisters rax_reg: dq 0 rbx_reg_offset equ $ - allregisters rbx_reg: dq 0 rcx_reg_offset equ $ - allregisters rcx_reg: dq 0 rdx_reg_offset equ $ - allregisters rdx_reg: dq 0 r8_reg_offset equ $ - allregisters r8_reg: dq 0 r9_reg_offset equ $ - allregisters r9_reg: dq 0 r10_reg_offset equ $ - allregisters r10_reg: dq 0 r11_reg_offset equ $ - allregisters r11_reg: dq 0 r12_reg_offset equ $ - allregisters r12_reg: dq 0 r13_reg_offset equ $ - allregisters r13_reg: dq 0 r14_reg_offset equ $ - allregisters r14_reg: dq 0 r15_reg_offset equ $ - allregisters r15_reg: dq 0 ;;; ;;; Segment registers ;;; cs_reg_offset equ $ - allregisters cs_reg: dq 0 ds_reg_offset equ $ - allregisters ds_reg: dq 0 ss_reg_offset equ $ - allregisters ss_reg: dq 0 es_reg_offset equ $ - allregisters es_reg: dq 0 fs_reg_offset equ $ - allregisters fs_reg: dq 0 gs_reg_offset equ $ - allregisters gs_reg: dq 0 ;;; ;;; CR registers ;;; cr0_reg_offset equ $ - allregisters cr0_reg: dq 0 ;; cr1_reg_offset equ $ - allregisters ;; cr1_reg: dq 0 cr2_reg_offset equ $ - allregisters cr2_reg: dq 0 cr3_reg_offset equ $ - allregisters cr3_reg: dq 0 cr4_reg_offset equ $ - allregisters cr4_reg: dq 0 ;; cr5_reg_offset equ $ - allregisters ;; cr5_reg: dq 0 ;; cr6_reg_offset equ $ - allregisters ;; cr6_reg: dq 0 ;; cr7_reg_offset equ $ - allregisters ;; cr7_reg: dq 0 cr8_reg_offset equ $ - allregisters cr8_reg: dq 0 ;;; ;;; XCR register ;;; xcr0_reg_offset equ $ - allregisters xcr0_reg: dq 0 ;;; ;;; MSR ;;; ;; ?? ;;; ;;; {G,L,I}DTR and TR ;;; ;; ?? ;;; ;;; MSW ;;; ;; ?? ;;; XSAVE? align 64 xsave_area_offset equ $ - allregisters xsave_area: times 2048 db 0 ;;; ;;; ;;; ;;; ;;; LET'S GO!! ;;; ;;; ;;; section .text global _start _start: save_all: ;; ;; rsp, rflags ;; mov [rsp_reg],rsp ; save stack pointer (yes, doing double duty here --- saving it for the sake of saving rsp, and getting ready for next trick mov rsp,rflags_reg+8 ; point stack at rflags_reg + 8 (the push ;; adds 8 *before*, not *after*) pushfq ; move rflags mov rsp,[rsp_reg] ; recover stack ;; ;; rsi, rdi ;; skip: mov [rsi_reg],rsi mov [rdi_reg],rdi ;; ;; rip ;; ;;; ALL CREDIT TO http://stackoverflow.com/questions/4062403/how-to-check-the-eip-value-with-assembly-language for the following trick to retrieve RIP cleanly: lea rax,[rip] ;; ;; rax, rbx, rcx, rdx ;; mov [rax_reg],rax mov [rbx_reg],rbx mov [rcx_reg],rcx mov [rdx_reg],rdx ;; ;; r8 - r15 ;; mov [r8_reg],r8 mov [r9_reg],r9 mov [r10_reg],r10 mov [r11_reg],r11 mov [r12_reg],r12 mov [r13_reg],r13 mov [r14_reg],r14 mov [r15_reg],r15 ;; ;; cs, ss, ds, es, fs, gs ;; mov rsp,cs_reg+8 ; clearly, I hope that the stack hasn't changed since it was saved ;; push ss ; apparently not possible in amd64 mode ;; push ds ; apparently not possible in amd64 mode ;; push es ; apparently not possible in amd64 mode push fs push gs mov rsp,[rsp_reg] ;; ;; CR0, CR2, CR3, CR4, CR8 ;; ;; appears to be a privilege issue in accessing? ;; mov rax,cr0 ;; mov [cr0_reg],eax ;; mov rax,cr1 ;; mov cr1_reg,cr1 ;; mov rax,cr2 ;; mov [cr2_reg],rax ;; mov rax,cr3 ;; mov [cr3_reg],rax ;; mov rax,cr4 ;; mov [cr4_reg],rax ;; mov rax,cr5 ;; mov [cr5_reg],rax ;; mov rax,cr6 ;; mov [cr6_reg],rax ;; mov rax,cr7 ;; mov [cr7_reg],rax ;; mov rax,cr8 ;; mov [cr8_reg],rax ;; mov rax,[rax_reg] ;; ;; XCR0 ;; mov eax,0x1 ; CPUID expects EAX to be set to 1 for this test cpuid test ecx,1< first, set EAX to 0x0 cpuid mov byte [max_cpuid],al hex1out max_cpuid,msg_max_cpuid_data mov [outstring],ebx mov [outstring+4],edx mov [outstring+8],ecx SYS_WRITE 1,processor_name,processor_name_len SYS_WRITE 1,outstring,12 SYS_WRITE 1,eoln,1 SYS_WRITE 1,msg_max_cpuid,msg_max_cpuid_len+2 SYS_WRITE 1,eoln,1 ;; Capabilities identification ;; First, define a macro that says what this is, what's next, and which register the flag is found in %macro CAPABILITY_WRITE 3 do_%1: SYS_WRITE 1,msg_%1,msg_%1_len SYS_WRITE 1,space_equal_space,3 test %3,1<<%1_VALUE je .around SYS_WRITE 1,yes_eoln,4 jmp do_%2 .around: SYS_WRITE 1,no_eoln,3 %endmacro eax_set_1: SYS_WRITE 1,msg_cpuid_eax_1_ecx_output,msg_cpuid_eax_1_ecx_output_len mov eax,0x1 ; EAX has to be set to 0x1 for "leaf 01"? cpuid mov [model_family_stepping],eax mov [brand_index],ebx ; yuck, this assumes that these bytes are consecutive, which is certainly true, but is still poor practice. However, I don't know how to address each byte in ebx separate (bl, bh, ??, ??) hex4out model_family_stepping,outstring SYS_WRITE 1,msg_model_family_stepping,msg_model_family_stepping_len SYS_WRITE 1,outstring,8 ; it takes eight characters to write four bytes in hex.... SYS_WRITE 1,eoln,1 hex1out brand_index,outstring SYS_WRITE 1,msg_brand_index,msg_brand_index_len SYS_WRITE 1,outstring,2 ; it takes two characters to write one byte in hex SYS_WRITE 1,eoln,1 hex1out CLFLUSH_instruction_cache_line_size,outstring SYS_WRITE 1,msg_CLFLUSH_instruction_cache_line_size,msg_CLFLUSH_instruction_cache_line_size_len SYS_WRITE 1,outstring,2 SYS_WRITE 1,eoln,1 hex1out logical_processor_count,outstring SYS_WRITE 1,msg_logical_processor_count,msg_logical_processor_count_len SYS_WRITE 1,outstring,2 SYS_WRITE 1,eoln,1 hex1out local_apic_id,outstring SYS_WRITE 1,msg_local_apic_id,msg_local_apic_id_len SYS_WRITE 1,outstring,2 SYS_WRITE 1,eoln,1 capabilities: CAPABILITY_WRITE SSE3,PCLMULQDQ,ecx CAPABILITY_WRITE PCLMULQDQ,DTES64,ecx CAPABILITY_WRITE DTES64,MONITOR_MWAIT,ecx CAPABILITY_WRITE MONITOR_MWAIT,DS_CPL,ecx CAPABILITY_WRITE DS_CPL,VMX,ecx CAPABILITY_WRITE VMX,SMX,ecx CAPABILITY_WRITE SMX,EIST,ecx CAPABILITY_WRITE EIST,TM2,ecx CAPABILITY_WRITE TM2,SSSE3,ecx CAPABILITY_WRITE SSSE3,CNXT_ID,ecx CAPABILITY_WRITE CNXT_ID,SDBG,ecx CAPABILITY_WRITE SDBG,FMA,ecx CAPABILITY_WRITE FMA,CMPXCHG16B,ecx CAPABILITY_WRITE CMPXCHG16B,xTPR,ecx CAPABILITY_WRITE xTPR,PDCM,ecx CAPABILITY_WRITE PDCM,PCID,ecx CAPABILITY_WRITE PCID,DCA,ecx CAPABILITY_WRITE DCA,SSE4_1,ecx CAPABILITY_WRITE SSE4_1,SSE4_2,ecx CAPABILITY_WRITE SSE4_2,x2APIC,ecx CAPABILITY_WRITE x2APIC,MOVBE,ecx CAPABILITY_WRITE MOVBE,POPCNT,ecx CAPABILITY_WRITE POPCNT,TSC_Deadline,ecx CAPABILITY_WRITE TSC_Deadline,AESNI,ecx CAPABILITY_WRITE AESNI,XSAVE,ecx CAPABILITY_WRITE XSAVE,OSXSAVE,ecx CAPABILITY_WRITE OSXSAVE,AVX,ecx CAPABILITY_WRITE AVX,F16C,ecx CAPABILITY_WRITE F16C,RDRAND,ecx CAPABILITY_WRITE RDRAND,ALWAYS_ZERO,ecx CAPABILITY_WRITE ALWAYS_ZERO,FPU,ecx SYS_WRITE 1,msg_cpuid_eax_1_edx_output,msg_cpuid_eax_1_edx_output_len CAPABILITY_WRITE FPU,VME,edx CAPABILITY_WRITE VME,DE,edx CAPABILITY_WRITE DE,PSE,edx CAPABILITY_WRITE PSE,TSC,edx CAPABILITY_WRITE TSC,MSR,edx CAPABILITY_WRITE MSR,PAE,edx CAPABILITY_WRITE PAE,MCE,edx CAPABILITY_WRITE MCE,CX8,edx CAPABILITY_WRITE CX8,APIC,edx CAPABILITY_WRITE APIC,SEP,edx CAPABILITY_WRITE SEP,MTRR,edx CAPABILITY_WRITE MTRR,PGE,edx CAPABILITY_WRITE PGE,MCA,edx CAPABILITY_WRITE MCA,CMOV,edx CAPABILITY_WRITE CMOV,PAT,edx CAPABILITY_WRITE PAT,PSE_36,edx CAPABILITY_WRITE PSE_36,PSN,edx CAPABILITY_WRITE PSN,CFLSH,edx CAPABILITY_WRITE CFLSH,DS,edx CAPABILITY_WRITE DS,ACPI,edx CAPABILITY_WRITE ACPI,MMX,edx CAPABILITY_WRITE MMX,FXSR,edx CAPABILITY_WRITE FXSR,SSE,edx CAPABILITY_WRITE SSE,SSE2,edx CAPABILITY_WRITE SSE2,SS,edx CAPABILITY_WRITE SS,HTT,edx CAPABILITY_WRITE HTT,TM,edx CAPABILITY_WRITE TM,PBE,edx CAPABILITY_WRITE PBE,last,edx do_last: eax_set_5: mov eax,0x5 cpuid mov word [mon_line_size_min],ax mov word [mon_line_size_max],bx hex2out mon_line_size_min,outstring SYS_WRITE 1,msg_mon_line_size_min,msg_mon_line_size_min_len SYS_WRITE 1,outstring,4 SYS_WRITE 1,eoln,1 hex2out mon_line_size_max,outstring SYS_WRITE 1,msg_mon_line_size_max,msg_mon_line_size_max_len SYS_WRITE 1,outstring,4 SYS_WRITE 1,eoln,1 eax_set_0x8: mov eax,0x80000000 cpuid ;; mov word [ ;; do_SSE3: ;; SYS_WRITE 1,msg_SSE3,msg_SSE3_len ;; SYS_WRITE 1,space_equal_space,3 ;; test ecx,1<