Copyright (C) Intel Corporation. All Rights Reserved. # Notices and Disclaimers Intel technologies may require enabled hardware, software or service activation. No product or component can be absolutely secure. Your costs and results may vary. All product plans and roadmaps are subject to change without notice. The products described may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request. Intel disclaims all express and implied warranties, including without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement, as well as any warranty arising from course of performance, course of dealing, or usage in trade. Code names are used by Intel to identify products, technologies, or services that are in development and not publicly available. These are not “commercial” names and not intended to function as trademarks. No license (express or implied, by estoppel or otherwise) to any intellectual property rights is granted by this document, with the sole exception that a) you may publish an unmodified copy and b) code, identified as Sample Code in this document is licensed subject to the Zero-Clause BSD open source license (0BSD), [https://opensource.org/licenses/0BSD](https://opensource.org/licenses/0BSD). You may create software implementations based on this document and in compliance with the foregoing that are intended to execute on the Intel product(s) referenced in this document. No rights are granted to create modifications or derivatives of this document. You may not use or facilitate the use of this document in connection with any infringement or other legal analysis concerning Intel products described herein. You agree to grant Intel a non-exclusive, royalty-free license to any patent claim thereafter drafted which includes subject matter disclosed herein. If you give Intel any comments or suggestions related to this document or the information contained in it, Intel can use them in any way and disclose them to anyone, without payment or other obligations to you. You represent and warrant that you own, or have sufficient rights from the owner of, any such comments or suggestions, and the intellectual property rights in them, to grant the above permission. © Intel Corporation. Intel, the Intel logo, and other Intel marks are trademarks of Intel Corporation or its subsidiaries. Other names and brands may be claimed as the property of others. The code in this file is not 'Sample Code'. Std::Boolean::Not Std::Integer::Le Std::Integer::Ne Std::Integer::Positive_Divide Std::Bits::Add_int Data_Size_Of_Current_Mode In_64Bit_Mode Mem_Fetch Report_Invalid_Opcode Instr_CALL_FAR Next_IP let offset := Mem_Fetch?(ip, operand_size); let segment_selector := Mem_Fetch?(ip + (operand_size / 8), 16); if not ((Data_Size_Of_Current_Mode() != 64)) then Report_Invalid_Opcode!(); endif; LockPrefix #UD Mode64 #UD Next_IP := ip + (operand_size / 8) + 2; Instr_CALL_FAR?(operand_size, offset, segment_selector); ptr16:v offset segment_selector let mode := Current_Mode(); var new_rsp := RSP; if mode in { Real_Address_Mode, Virtual_8086_Mode } then if operand_size == 32 then new_rsp := Push_Stack?(SS, new_rsp, CS, 32, 32, Zero_Extend(CS.selector, 32)); new_rsp := Push_Stack?(SS, new_rsp, CS, 32, 32, Next_IP[0 +: 32]); elsif operand_size == 16 then new_rsp := Push_Stack?(SS, new_rsp, CS, 16, 16, CS.selector); new_rsp := Push_Stack?(SS, new_rsp, CS, 16, 16, Next_IP[0 +: 16]); else Std::Unreachable(); endif; let new_cs := Load_Real_Or_VM86_Segment(mode, segment_selector, CS); let new_rip := Zero_Extend(offset, 64); Check_New_RIP?(new_cs, new_rip); Branch_Far(new_cs, new_rip); RSP := new_rsp; else let new_cs_selector : Segment_Selector := segment_selector; var new_cs := Load_Segment_Descriptor?(new_cs_selector, CS); var stack_access_size := operand_size; var new_rip := Zero_Extend(offset, 64); let calling_procedure := new_cs; if Is_Task_Segment(new_cs) then Handle_Task?(new_cs, Task_Switch_Call, Next_IP); else let seg_type := Get_Segment_Type(new_cs); case seg_type of when System16Bit_Call_Gate, System_Call_Gate => if CR4.FRED == 0b1 or Unsigned(calling_procedure.descriptor.DPL) < CPL or Unsigned(calling_procedure.descriptor.DPL) < Unsigned(calling_procedure.selector.RPL) then Report_General_Protection_Exception!(Get_Error_Code_From_Selector(calling_procedure.selector)); endif; (new_cs, new_rip) := Get_Target_From_Gate?(calling_procedure); stack_access_size := Get_System_Segment_Size(calling_procedure); if Unsigned(new_cs.descriptor.DPL) > CPL then Report_General_Protection_Exception!(Get_Error_Code_From_Selector(new_cs.selector)); endif; when Conforming_Code_Segment => if Unsigned(new_cs.descriptor.DPL) > CPL then Report_General_Protection_Exception!(Get_Error_Code_From_Selector(new_cs.selector)); endif; when Non_Conforming_Code_Segment => if Unsigned(new_cs.selector.RPL) > CPL or Unsigned(new_cs.descriptor.DPL) != CPL then Report_General_Protection_Exception!(Get_Error_Code_From_Selector(new_cs.selector)); endif; otherwise => Report_General_Protection_Exception!(Get_Error_Code_From_Selector(new_cs.selector)); endcase; Code_Segment_Checks?(new_cs); if new_cs.descriptor.A == 0b0 then new_cs := Set_Segment_Access_Bit?(new_cs); endif; var new_ss := SS; var privilege_level_change := False; if Is_Non_Conforming_Code_Segment(new_cs) and Unsigned(new_cs.descriptor.DPL) < CPL then (new_ss, new_rsp) := Call_More_Privilege?(new_cs, calling_procedure.descriptor.Parameter_count, stack_access_size); privilege_level_change := True; else new_cs.selector.RPL := CPL[0 +: 2]; endif; case stack_access_size of when 16 => new_rsp := Push_Stack?(new_ss, new_rsp, new_cs, 16, 16, CS.selector); new_rsp := Push_Stack?(new_ss, new_rsp, new_cs, 16, 16, Next_IP[0 +: 16]); when 32 => new_rsp := Push_Stack?(new_ss, new_rsp, new_cs, 32, 32, Zero_Extend(CS.selector, 32)); new_rsp := Push_Stack?(new_ss, new_rsp, new_cs, 32, 32, Next_IP[0 +: 32]); when 64 => new_rsp := Push_Stack?(new_ss, new_rsp, new_cs, 64, 64, Zero_Extend(CS.selector, 64)); new_rsp := Push_Stack?(new_ss, new_rsp, new_cs, 64, 64, Next_IP); endcase; Check_New_RIP?(new_cs, new_rip); if privilege_level_change then if CET::Is_Shadow_Stack_Enabled(CPL) and CPL == 3 then IA32_PL3_SSP := if IA32_EFER.LMA == 0b1 then Set_Canonical_Wrt_Paging_Mode(SSP) else SSP; endif; if CET::Is_Shadow_Stack_Enabled(Unsigned(new_cs.descriptor.DPL)) then let new_ssp := IA32_SSP[new_cs.descriptor.DPL]; if not CET::Is_Valid_Shadow_Stack_Address(new_ssp, new_cs) or not Is_Aligned(new_ssp, 8) then Report_General_Protection_Exception!(Zero(32)); endif; // Token and CS:LIP:oldSSP pushed on shadow stack // must be contained in a naturally aligned 32-byte region let new_ssp_after_push := new_ssp - 24; if new_ssp[63:5] != new_ssp_after_push[63:5] then Report_General_Protection_Exception!(Zero(32)); endif; if not CET::Shadow_Stack_Set_Token_Busy_Bit?(new_ssp) then Report_General_Protection_Exception!(Zero(32)); endif; SSP := if SS.descriptor.DPL != 0b11 then CET::Shadow_Stack_Switch?(new_ssp, Zero_Extend(CS.selector, 64), Next_IP, new_cs) else new_ssp; endif; else if CET::Is_Shadow_Stack_Enabled(CPL) then if not Is_64Bit_Code_Segment(new_cs) and not Is_Zero(SSP[63:32]) then Report_General_Protection_Exception!(Zero(32)); endif; SSP := CET::Shadow_Stack_Switch?(SSP, Zero_Extend(CS.selector, 64), Next_IP, new_cs); endif; endif; if Is_End_Branch_Enabled(CPL) then CET::Set_Tracker_Status(CPL); endif; Branch_Far(new_cs, new_rip); Update_Stack_Pointer(new_ss, new_rsp); endif; endif; Std::Boolean::Not Std::Boolean::Strict_And Std::Boolean::Strict_Or Std::Integer::Eq Std::Integer::Gt Std::Integer::Lt Std::Integer::Ne Std::Bits::Unsigned Std::Bits::Eq Std::Bits::Is_Zero Std::Bits::Ne Std::Bits::Subtract_int Std::Bits::Zero_Extend Std::Bits::Zero Std::Unreachable Branch_Far CET::Is_Shadow_Stack_Enabled CET::Is_Valid_Shadow_Stack_Address CET::Set_Tracker_Status CET::Shadow_Stack_Set_Token_Busy_Bit CET::Shadow_Stack_Switch Call_More_Privilege Check_New_RIP Code_Segment_Checks Current_Mode Get_Error_Code_From_Selector Get_Segment_Type Get_System_Segment_Size Get_Target_From_Gate Handle_Task IA32_SSP Is_64Bit_Code_Segment Is_Aligned Is_End_Branch_Enabled Is_Non_Conforming_Code_Segment Is_Task_Segment Load_Real_Or_VM86_Segment Load_Segment_Descriptor Push_Stack Report_General_Protection_Exception Set_Canonical_Wrt_Paging_Mode Set_Segment_Access_Bit Update_Stack_Pointer RSP RSP_write True False CS Real_Address_Mode CPL Virtual_8086_Mode SSP CR4 IA32_EFER SS Task_Switch_Call IA32_PL3_SSP Conforming_Code_Segment Non_Conforming_Code_Segment System16Bit_Call_Gate System_Call_Gate Next_IP Std::Boolean::Not Std::Bits::Add_int Std::Bits::Sign_Extend Mem_Fetch Report_Invalid_Opcode Instr_CALL_NEAR True False Next_IP let operand_size := 64; let is_relative := True; let is_indirect := False; let is_no_track := False; let src := Sign_Extend(Mem_Fetch?(ip, 32), operand_size); if not (not context.rex2_prefix_present) then Report_Invalid_Opcode!(); endif; LockPrefix #UD Next_IP := ip + 4; Instr_CALL_NEAR?(operand_size, context, src, is_relative, is_indirect, is_no_track); rel32 src is_relative is_indirect is_no_track let new_rip := if is_relative then Relative_Branch_Wrap(context.operand_size, Next_IP + Sign_Extend(src, 64)) else Zero_Extend(src, 64); let update_shadow_stack := CET::Is_Shadow_Stack_Enabled(CPL) and (not is_relative or not Is_Zero(src)); if not update_shadow_stack then Check_New_RIP?(CS, new_rip); endif; let new_rsp := Push_Stack?(SS, RSP, CS, operand_size, operand_size, Next_IP[0 +: operand_size]); if update_shadow_stack then Check_New_RIP?(CS, new_rip); SSP := CET::Shadow_Stack_Push?(SSP, Next_IP[0 +: Max(operand_size, 32)]); endif; RSP := new_rsp; Branch_Near(new_rip); if is_indirect and Is_End_Branch_Enabled_And_Not_Suppressed(CPL) then if IA32_CET[CPL].NO_TRACK_EN == 0b0 or not is_no_track then CET::Set_Tracker_Status(CPL); endif; endif; Std::Boolean::Not Std::Boolean::Strict_And Std::Boolean::Strict_Or Std::Integer::Le Std::Integer::Max Std::Bits::Add Std::Bits::Eq Std::Bits::Is_Zero Std::Bits::Sign_Extend Std::Bits::Zero_Extend Branch_Near CET::Is_Shadow_Stack_Enabled CET::Set_Tracker_Status CET::Shadow_Stack_Push Check_New_RIP IA32_CET Is_End_Branch_Enabled_And_Not_Suppressed Push_Stack Relative_Branch_Wrap RSP RSP_write CS CPL SSP SS Next_IP Std::Integer::Le Std::Integer::Min Std::Integer::Positive_Divide Std::Bits::Add_int Std::Bits::Sign_Extend In_64Bit_Mode Mem_Fetch Report_Invalid_Opcode Instr_CALL_NEAR True False Next_IP let is_relative := True; let is_indirect := False; let is_no_track := False; let src := Sign_Extend(Mem_Fetch?(ip, Min(operand_size, 32)), operand_size); LockPrefix #UD Mode64 #UD Next_IP := ip + (Min(operand_size, 32) / 8); Instr_CALL_NEAR?(operand_size, context, src, is_relative, is_indirect, is_no_track); relz src is_relative is_indirect is_no_track Std::Integer::Add Std::Bits::Append Read_GPR Report_Invalid_Opcode Instr_CALL_NEAR True False Next_IP let is_relative := False; let is_indirect := True; let is_no_track := context.no_track_prefix; let src := Read_GPR(context.rex_b4 ++ context.rex_b3 ++ rm, operand_size); LockPrefix #UD Next_IP := ip; Instr_CALL_NEAR?(operand_size, context, src, is_relative, is_indirect, is_no_track); rv src ModRM:r/m is_relative is_indirect is_no_track Effective_Address Handle_RIP_Relative_Address Logical_Mem_Read Report_Invalid_Opcode Instr_CALL_NEAR True False Memory_Read Normal_Alignment Next_IP let is_relative := False; let is_indirect := True; let is_no_track := context.no_track_prefix; let disp8n := 1; let (ea_offset, segment, next_ip0, is_rip_relative) := Effective_Address?(address_size, context, mod, rm, disp8n, ip); let effective_address := Handle_RIP_Relative_Address(address_size, is_rip_relative, ea_offset, next_ip0); LockPrefix #UD let src := Logical_Mem_Read?(segment, effective_address, operand_size); Next_IP := next_ip0; Instr_CALL_NEAR?(operand_size, context, src, is_relative, is_indirect, is_no_track); mv src ModRM:r/m is_relative is_indirect is_no_track Std::Integer::Le Std::Integer::Positive_Divide Std::Bits::Add_int Effective_Address Handle_RIP_Relative_Address Logical_Mem_Read Report_Invalid_Opcode Instr_CALL_FAR False Memory_Read Normal_Alignment Next_IP let disp8n := 1; let (ea_offset, segment, next_ip0, is_rip_relative) := Effective_Address?(address_size, context, mod, rm, disp8n, ip); let effective_address := Handle_RIP_Relative_Address(address_size, is_rip_relative, ea_offset, next_ip0); LockPrefix #UD let offset := Logical_Mem_Read?(segment, effective_address, operand_size); let segment_selector := Logical_Mem_Read?(segment, effective_address + ((operand_size) / 8), 16); Next_IP := next_ip0; Instr_CALL_FAR?(operand_size, offset, segment_selector); m16:v offset ModRM:r/m segment_selector ModRM:r/m branch/call Operand is sign-extended to operand_size bits.