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.