Skip to content

Commit

Permalink
Update by Mar.19th, 2020
Browse files Browse the repository at this point in the history
Complete remastering of CPUID caching architecture on SVM-Core.
Update documents.
  • Loading branch information
Zero-Tang committed Mar 19, 2020
1 parent ba7d17b commit 33194fb
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 83 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Also note that, you have to create certain directories required by the batch com
You may download the WDK 7.1.0 from Microsoft: https://www.microsoft.com/en-us/download/details.aspx?id=11800 <br>
Presets for Free/Release build are available. Please note that the compiled binary under Free build does not come along with a digital signature. You might have to sign it yourself.

# EFI Application
## EFI Application
To build a EFI Application, you should install LLVM and TianoCore EDK II. To install TianoCore EDK II, you may download latest release source code and extract to path "C:\UefiDKII". <br>
You may download LLVM from GitHub: https://github.com/llvm/llvm-project/releases <br>
You may download EDK II from GitHub: https://github.com/tianocore/edk2/releases <br>
Expand All @@ -50,14 +50,17 @@ If you use the digital signature provided in NoirVisor's repository, then you sh
Use a USB flash stick and setup with GUID Partition Table (GPT). Construct a partition and format it info FAT32 file system. After you build the image, you should copy it to \EFI\BOOT\bootx64.efi. <br>
As the USB flash stick is ready, enter your firmware settings and set it prior to the operating system.

# Detection of NoirVisor
As specified in AMD64 Architecture Programming Manual, CPUID.EAX=1.ECX[bit 31] indicates hypervisor presence. So NoirVisor will set this bit. For CPUID instruction, since AMD defines that function leaves 0x40000000-0x400000FF are reserved for hypervisor use, we will use them. Most hypervisors defines leaf 0x40000000 is used to identify hypervisor vendor. The string constructed by register sequence EBX-ECX-EDX is used to identify vendor of hypervisor. For example, VMware hypervisor vendor string is "VMwareVMware". In NoirVisor, hypervisor vendor string is defined as "NoirVisor ZT".

# Supported Platforms
NoirVisor is designed to be cross-platform. It can be built to a kernel-mode component of an operating system, or even as a software with bootstrap running on bare-metal. <br>
Currently, NoirVisor supports the Windows Operating System newer than or same as Windows XP, running as a kernel-mode driver. <br>
If there is already a hypervisor running in the system, make sure it supports native virtualization nesting.

# Development Status
Project NoirVisor has six future development plans: <br>
- Remaster CPUID-caching architecture with a flexible design. <br>
- Remaster CPUID-caching architecture with a flexible design for Intel VT-x. <br>
- Develop Nested Paging with Stealth Hook on SVM-Engine for NoirVisor. <br>
- Develop Nested Virtualization. <br>
- Develop Hypervisor-Platform compatible hypervisor for Windows 10 Redstone. <br>
Expand All @@ -68,7 +71,7 @@ Project NoirVisor has six future development plans: <br>
- Stealth SSDT Hook (NtOpenProcess Hook) on 64-bit Windows, both Intel VT-x and AMD-V.
- Stealth Inline Hook (NtSetInformationFile Hook) on 64-bit Windows, Intel VT-x.
- Tagged Translation Lookaside Buffer by ASID/VPID feature.
- CPUID caching architecture. (First Design, not quite efficient.)
- Efficient CPUID caching architecture on AMD-V.
- Critical Hypervisor Protection.
- Software-Level Code Integrity Enforcement.
- Hardware-Level Code Integrity Enforcement, both Intel EPT and AMD NPT.
Expand Down
8 changes: 8 additions & 0 deletions build_prep.bat
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,13 @@ echo Making Directories for NoirVisor Free Build, 32-Bit Windows
mkdir .\bin\compfre_win7x86
mkdir .\bin\compfre_win7x86\Intermediate

echo Making Directories for NoirVisor Checked Build, 64-Bit UEFI
mkdir .\bin\compchk_uefix64
mkdir .\bin\compchk_uefix64\Intermediate

echo Making Directories for NoirVisor Free Build, 64-Bit UEFI
mkdir .\bin\compfre_uefix64
mkdir .\bin\compfre_uefix64\Intermediate

echo Preparation Completed!
pause.
2 changes: 2 additions & 0 deletions src/include/amd64.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@
// This is used for defining AMD64 architectural cpuid flags.
#define amd64_cpuid_svm 2
#define amd64_cpuid_svm_bit 0x4
#define amd64_cpuid_hv_presence 31
#define amd64_cpuid_hv_presence_bit 0x80000000

// CPUID flags for SVM Features
#define amd64_cpuid_npt 0
Expand Down
9 changes: 8 additions & 1 deletion src/include/svm_hvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

#include <nvdef.h>

#define noir_svm_cpuid_std_submask 0x2080
#define noir_svm_cpuid_ext_submask 0x20000000

// Definition of vmmcall Codes
#define noir_svm_callexit 1

Expand Down Expand Up @@ -51,6 +54,7 @@ typedef struct _noir_svm_cached_cpuid
void** hvm_leaf; // 0x40000000-0x400000FF
void** ext_leaf; // 0x80000000-0x800000FF
void** res_leaf; // 0xC0000000-0xC00000FF
void* cache_base;
// Maximum Counts.
u32 max_leaf[4];
}noir_svm_cached_cpuid,*noir_svm_cached_cpuid_p;
Expand All @@ -65,6 +69,7 @@ typedef struct _noir_svm_vcpu
{
memory_descriptor vmcb;
memory_descriptor hsave;
memory_descriptor hvmcb;
void* hv_stack;
noir_svm_hvm_p relative_hvm;
u32 proc_id;
Expand All @@ -78,6 +83,7 @@ typedef struct _noir_svm_vcpu
typedef struct _noir_svm_initial_stack
{
u64 guest_vmcb_pa;
u64 host_vmcb_pa;
noir_svm_vcpu_p vcpu;
u32 proc_id;
}noir_svm_initial_stack,*noir_svm_initial_stack_p;
Expand All @@ -88,4 +94,5 @@ void fastcall nvc_svm_reserved_cpuid_handler(noir_gpr_state_p gpr_state,noir_svm
bool nvc_svm_build_cpuid_handler(u32 std_count,u32 hvm_count,u32 ext_count,u32 res_count);
void nvc_svm_teardown_cpuid_handler();
bool nvc_svm_build_exit_handler();
void nvc_svm_teardown_exit_handler();
void nvc_svm_teardown_exit_handler();
void nvc_svm_build_cpuid_cache_per_vcpu(noir_svm_vcpu_p vcpu);
1 change: 0 additions & 1 deletion src/svm_core/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ Real-Time CI is now implemented by AMD Nested Paging.
# Future Feature (Roadmap)
In future, NoirVisor has following plans:

- Remaster CPUID-caching architecture with flexible design
- Implement SVM-Nesting (This will be a long term project.)
- Implement NPT-based Stealth Inline Hook

Expand Down
102 changes: 90 additions & 12 deletions src/svm_core/svm_cpuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,69 @@
Class 3: Reserved Leaf Function Range: 0xC0000000-0xFFFFFFFF
*/

/*
Build cache for CPUID instruction per virtual processor.
Generic Rules:
1. Use cpuid instruction with ecx=0 to initialize generic data.
2. If we have special treatings, make specific initializations.
*/
void nvc_svm_build_cpuid_cache_per_vcpu(noir_svm_vcpu_p vcpu)
{
noir_svm_cpuid_default_p info;
u32 i;
// Generic Initialization
for(i=0;i<vcpu->cpuid_cache.max_leaf[std_leaf_index];i++)
{
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.std_leaf[i];
noir_cpuid(i,0,&info->eax,&info->ebx,&info->ecx,&info->edx);
}
for(i=0;i<vcpu->cpuid_cache.max_leaf[ext_leaf_index];i++)
{
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.ext_leaf[i];
noir_cpuid(i+0x80000000,0,&info->eax,&info->ebx,&info->ecx,&info->edx);
}
// Specific Initialization
// Function Leaf 0x1 - Processor and Processor Feature Identifiers
// We indicate hypervisor presense here.
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.std_leaf[std_proc_feature];
noir_bts(&info->ecx,amd64_cpuid_hv_presence);
// Function leaf 0xD - Processor Extended State Enumeration
// There are multiple subfunctions in this leaf.
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.std_leaf[std_pestate_enum];
noir_cpuid(std_pestate_enum,1,&info[1].eax,&info[1].ebx,&info[1].ecx,&info[1].edx); // Sub-leaf 1
noir_cpuid(std_pestate_enum,2,&info[2].eax,&info[2].ebx,&info[2].ecx,&info[2].edx); // Sub-leaf 2
noir_cpuid(std_pestate_enum,62,&info[3].eax,&info[3].ebx,&info[3].ecx,&info[3].edx); // Sub-leaf 62
// Function leaf 0x40000000 - Maximum Hypervisor Function Number and Vendor String
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.hvm_leaf[hvm_max_num_vstr];
info->eax=0; // We have this leaf only.
// Vendor String="NoirVisor ZT"
info->ebx='rioN';
info->ecx='osiV';
info->edx='TZ r';
// Function leaf 0x80000001 - Extended Processor and Processor Feature Identifiers
// By now, we might have to indicate no support to nested virtualization.
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.ext_leaf[ext_proc_feature];
noir_btr(&info->ecx,amd64_cpuid_svm);
// Function leaf 0x8000000A - SVM Features
// Erase some features that we don't support.
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.ext_leaf[ext_svm_features];
info->ebx--; // Decrement available ASID by 1.
noir_btr(&info->edx,amd64_cpuid_npt); // NoirVisor does not have an algorithm to it.
// Function leaf 0x8000001D - Cache Topology Information
// This is variable count of subfunctions.
info=(noir_svm_cpuid_default_p)vcpu->cpuid_cache.ext_leaf[ext_cache_topinf];
for(i=1;(info[i-1].eax & 0x1f)!=0;i++)
{
if(i==8)
{
nv_panicf("Overflow in Cache Topology CPUID Leaf!\n");
break;
}
noir_cpuid(ext_cache_topinf+0x80000000,i,&info[i].eax,&info[i].ebx,&info[i].ecx,&info[i].edx);
}
}

// Reserved Function Leaf.
// This would clear the CPUID data to zero.
void fastcall nvc_svm_reserved_cpuid_handler(noir_gpr_state_p gpr_state,noir_svm_vcpu_p vcpu)
Expand Down Expand Up @@ -105,6 +168,18 @@ void static fastcall nvc_svm_cpuid_std_vendor_string(noir_gpr_state_p gpr_state,
by now, is not in conformation.
*/

// Function Leaf: 0x40000000 - Maxinum Number of Leaves and Vendor String
void static fastcall nvc_svm_cpuid_hvm_vendor_string(noir_gpr_state_p gpr_state,noir_svm_vcpu_p vcpu)
{
noir_svm_cpuid_max_num_vstr_p cache=(noir_svm_cpuid_max_num_vstr_p)vcpu->cpuid_cache.hvm_leaf[hvm_max_num_vstr];
// EAX - Maximum Number of CPUID
*(u32*)&gpr_state->rax=cache->maximum;
// EBX-ECX-EDX -> "NoirVisor ZT" by default
*(u32*)&gpr_state->rbx=*(u32*)&cache->vendor_string[0];
*(u32*)&gpr_state->rcx=*(u32*)&cache->vendor_string[4];
*(u32*)&gpr_state->rdx=*(u32*)&cache->vendor_string[8];
}

/*
Extended Leaf Functions:
Expand All @@ -129,32 +204,32 @@ void static fastcall nvc_svm_cpuid_ext_brand_string_p1(noir_gpr_state_p gpr_stat
{
char* brand=(char*)vcpu->cpuid_cache.ext_leaf[ext_brand_str_p1];
// Sorted by EAX-EBX-ECX-EDX
*(u32*)&gpr_state->rax=*(u32*)brand[0x0];
*(u32*)&gpr_state->rbx=*(u32*)brand[0x4];
*(u32*)&gpr_state->rcx=*(u32*)brand[0x8];
*(u32*)&gpr_state->rdx=*(u32*)brand[0xC];
*(u32*)&gpr_state->rax=*(u32*)&brand[0x0];
*(u32*)&gpr_state->rbx=*(u32*)&brand[0x4];
*(u32*)&gpr_state->rcx=*(u32*)&brand[0x8];
*(u32*)&gpr_state->rdx=*(u32*)&brand[0xC];
}

// Function Leaf: 0x80000003 - Processor Name String (Part II)
void static fastcall nvc_svm_cpuid_ext_brand_string_p2(noir_gpr_state_p gpr_state,noir_svm_vcpu_p vcpu)
{
char* brand=(char*)vcpu->cpuid_cache.ext_leaf[ext_brand_str_p2];
// Sorted by EAX-EBX-ECX-EDX
*(u32*)&gpr_state->rax=*(u32*)brand[0x0];
*(u32*)&gpr_state->rbx=*(u32*)brand[0x4];
*(u32*)&gpr_state->rcx=*(u32*)brand[0x8];
*(u32*)&gpr_state->rdx=*(u32*)brand[0xC];
*(u32*)&gpr_state->rax=*(u32*)&brand[0x0];
*(u32*)&gpr_state->rbx=*(u32*)&brand[0x4];
*(u32*)&gpr_state->rcx=*(u32*)&brand[0x8];
*(u32*)&gpr_state->rdx=*(u32*)&brand[0xC];
}

// Function Leaf: 0x80000004 - Processor Name String (Part III)
void static fastcall nvc_svm_cpuid_ext_brand_string_p3(noir_gpr_state_p gpr_state,noir_svm_vcpu_p vcpu)
{
char* brand=(char*)vcpu->cpuid_cache.ext_leaf[ext_brand_str_p3];
// Sorted by EAX-EBX-ECX-EDX
*(u32*)&gpr_state->rax=*(u32*)brand[0x0];
*(u32*)&gpr_state->rbx=*(u32*)brand[0x4];
*(u32*)&gpr_state->rcx=*(u32*)brand[0x8];
*(u32*)&gpr_state->rdx=*(u32*)brand[0xC];
*(u32*)&gpr_state->rax=*(u32*)&brand[0x0];
*(u32*)&gpr_state->rbx=*(u32*)&brand[0x4];
*(u32*)&gpr_state->rcx=*(u32*)&brand[0x8];
*(u32*)&gpr_state->rdx=*(u32*)&brand[0xC];
}

// Function Leaf: 0x8000000A - SVM Revision and Feature Id
Expand All @@ -178,15 +253,18 @@ bool nvc_svm_build_cpuid_handler(u32 std_count,u32 hvm_count,u32 ext_count,u32 r
if(svm_cpuid_handlers)
{
svm_cpuid_handlers[std_leaf_index]=noir_alloc_nonpg_memory(sizeof(void*)*std_count);
svm_cpuid_handlers[hvm_leaf_index]=noir_alloc_nonpg_memory(sizeof(void*)*hvm_count);
svm_cpuid_handlers[ext_leaf_index]=noir_alloc_nonpg_memory(sizeof(void*)*ext_count);
if(svm_cpuid_handlers[std_leaf_index] && svm_cpuid_handlers[ext_leaf_index])
{
// Initialize CPUID handlers with default handlers.
// Using stos instruction could accelerate the initialization.
noir_stosp(svm_cpuid_handlers[std_leaf_index],(ulong_ptr)nvc_svm_default_cpuid_handler,std_count);
noir_stosp(svm_cpuid_handlers[hvm_leaf_index],(ulong_ptr)nvc_svm_default_cpuid_handler,hvm_count);
noir_stosp(svm_cpuid_handlers[ext_leaf_index],(ulong_ptr)nvc_svm_default_cpuid_handler,ext_count);
// Default Handlers are set. Setup the customized handlers here.
svm_cpuid_handlers[ext_leaf_index][ext_svm_features]=nvc_svm_cpuid_ext_svm_feature_id;
svm_cpuid_handlers[hvm_leaf_index][hvm_max_num_vstr]=nvc_svm_cpuid_hvm_vendor_string;
return true;
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/svm_core/svm_cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

#include <nvdef.h>

// This is AMD Specific
#define noir_svm_std_cpuid_submask 0x00002080
#define noir_svm_ext_cpuid_submask 0x20000000

// Index of Standard Leaves
#define std_max_num_vstr 0x0
#define std_proc_feature 0x1
Expand Down Expand Up @@ -41,6 +45,9 @@
#define ext_proc_topoinf 0x1E
#define ext_mem_crypting 0x1F

// Index of Hypervisor Leaves
#define hvm_max_num_vstr 0x0

typedef struct _noir_svm_cpuid_default
{
u32 eax;
Expand All @@ -51,14 +58,15 @@ typedef struct _noir_svm_cpuid_default

typedef struct _noir_svm_cpuid_max_num_vstr
{
char* vendor_string;
u32 maximum;
char vendor_string[12];
}noir_svm_cpuid_max_num_vstr,*noir_svm_cpuid_max_num_vstr_p;

typedef struct _noir_svm_cpuid_svm_feature_id
{
u32 rev_number;
u32 avail_asid;
u32 reserved;
u32 feature_id;
}noir_svm_cpuid_svm_feature_id,*noir_svm_cpuid_svm_feature_id_p;

Expand Down
Loading

0 comments on commit 33194fb

Please sign in to comment.