Skip to content
This repository was archived by the owner on Jan 28, 2023. It is now read-only.

Added support for Linux hosts #108

Merged
merged 5 commits into from
Nov 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# macOS
.DS_Store

# Linux
*.o
*.cmd
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ matrix:
- cd platforms/darwin
- xcodebuild -configuration Debug -sdk macosx10.14

- name: "haxm-linux"
os: linux
dist: trusty
sudo: false
before_install:
- sudo apt-get update
- sudo apt-get install -y linux-headers-`uname -r`
- wget http://mirrors.kernel.org/ubuntu/pool/universe/n/nasm/nasm_2.13.02-0.1_amd64.deb
- sudo apt-get install -y dpkg
- sudo dpkg -i nasm_2.13.02-0.1_amd64.deb
script:
- cd platforms/linux
- make -j$(nproc)

exclude: # TODO: Currently TravisCI does not support full VS/EWDK on Windows
- name: "haxm-windows"
os: windows
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ release, you can get it [here][github-haxm-latest-release].
## Usage

Detailed instructions for building and testing HAXM can be found at:
* [Manual for Linux](docs/manual-linux.md)
* [Manual for macOS](docs/manual-macos.md)
* [Manual for Windows](docs/manual-windows.md)

Expand Down
2 changes: 1 addition & 1 deletion core/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ uint32_t load_vmcs(struct vcpu_t *vcpu, preempt_flag *flags)
/* when wake up from sleep, we need the barrier, as vm operation
* are not serialized instructions.
*/
smp_mb();
hax_smp_mb();

cpu_data = current_cpu_data();

Expand Down
4 changes: 2 additions & 2 deletions core/ept.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ static void invept_smpfunc(struct invept_bundle *bundle)
{
struct per_cpu_data *cpu_data;

smp_mb();
hax_smp_mb();
cpu_data = current_cpu_data();
cpu_data->invept_res = VMX_SUCCEED;

Expand Down Expand Up @@ -373,7 +373,7 @@ void invept(hax_vm_t *hax_vm, uint type)

bundle.type = type;
bundle.desc = &desc;
smp_call_function(&cpu_online_map, (void (*)(void *))invept_smpfunc,
hax_smp_call_function(&cpu_online_map, (void (*)(void *))invept_smpfunc,
&bundle);

/*
Expand Down
6 changes: 3 additions & 3 deletions core/hax.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ struct hax_t *hax;
extern hax_atomic_t vmx_cpu_num, vmx_enabled_num;
static void hax_enable_vmx(void)
{
smp_call_function(&cpu_online_map, cpu_init_vmx, NULL);
hax_smp_call_function(&cpu_online_map, cpu_init_vmx, NULL);
}

static void hax_disable_vmx(void)
{
smp_call_function(&cpu_online_map, cpu_exit_vmx, NULL);
hax_smp_call_function(&cpu_online_map, cpu_exit_vmx, NULL);
}

static void free_cpu_vmxon_region(void)
Expand Down Expand Up @@ -410,7 +410,7 @@ static void hax_pmu_init(void)
int ref_cpu_id = -1;

// Execute cpu_pmu_init() on each logical processor of the host CPU
smp_call_function(&cpu_online_map, cpu_pmu_init, NULL);
hax_smp_call_function(&cpu_online_map, cpu_pmu_init, NULL);

// Find the common APM version supported by all host logical processors
// TODO: Theoretically we should do the same for other APM parameters
Expand Down
2 changes: 1 addition & 1 deletion core/ia32.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ void ia32_wrmsr(uint32_t reg, uint64_t val)
#endif
}

uint64_t rdtsc(void)
uint64_t ia32_rdtsc(void)
{
#ifdef HAX_ARCH_X86_32
struct qword_val val = { 0 };
Expand Down
2 changes: 1 addition & 1 deletion core/ia32_ops.asm
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ function __nmi, 0
int 2h
ret

function __fls, 1
function asm_fls, 1
xor reg_ret_32, reg_ret_32
bsr reg_ret_32, reg_arg1_32
ret
Expand Down
4 changes: 2 additions & 2 deletions core/include/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ struct per_cpu_data {

/*
* These fields are used to record the result of certain VMX instructions
* when they are used in a function wrapped by smp_call_function(). This is
* when they are used in a function wrapped by hax_smp_call_function(). This is
* because it is not safe to call hax_error(), etc. (whose underlying
* implementation may use a lock) from the wrapped function to log a
* failure; doing so may cause a deadlock and thus a host reboot, especially
* on macOS, where mp_rendezvous_no_intrs() (the legacy Darwin API used by
* HAXM to implement smp_call_function()) is known to be prone to deadlocks:
* HAXM to implement hax_smp_call_function()) is known to be prone to deadlocks:
* https://lists.apple.com/archives/darwin-kernel/2006/Dec/msg00006.html
*/
vmx_result_t vmxon_res;
Expand Down
4 changes: 2 additions & 2 deletions core/include/emulate_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
(0 * FASTOP_ALIGN))

/* Instruction handlers */
typedef void(__cdecl em_handler_t)(void);
typedef void(ASMCALL em_handler_t)(void);
em_handler_t em_not;
em_handler_t em_neg;
em_handler_t em_inc;
Expand Down Expand Up @@ -72,7 +72,7 @@ em_handler_t em_bextr;
em_handler_t em_andn;

/* Dispatch handlers */
void __cdecl fastop_dispatch(void *handler, uint64_t *dst,
void ASMCALL fastop_dispatch(void *handler, uint64_t *dst,
uint64_t *src1, uint64_t *src2, uint64_t *flags);

#endif /* HAX_CORE_EMULATE_OPS_H_ */
4 changes: 2 additions & 2 deletions core/include/ia32.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ void ASMCALL asm_fxrstor(mword *addr);
void ASMCALL asm_cpuid(union cpuid_args_t *state);

void ASMCALL __nmi(void);
uint32_t ASMCALL __fls(uint32_t bit32);
uint32_t ASMCALL asm_fls(uint32_t bit32);

uint64_t ia32_rdmsr(uint32_t reg);
void ia32_wrmsr(uint32_t reg, uint64_t val);

uint64_t rdtsc(void);
uint64_t ia32_rdtsc(void);

void fxinit(void);
void fxsave(mword *addr);
Expand Down
2 changes: 1 addition & 1 deletion core/include/vmx.h
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ void vmx_vmwrite(struct vcpu_t *vcpu, const char *name,
vmwrite(vcpu, GUEST_##seg##_AR, tmp_ar); \
}

#elif defined(HAX_PLATFORM_DARWIN)
#else
#define VMWRITE_SEG(vcpu, seg, val) ({ \
uint32_t tmp_ar = val.ar; \
if (tmp_ar == 0) \
Expand Down
2 changes: 1 addition & 1 deletion core/intr_exc.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ uint32_t vcpu_get_pending_intrs(struct vcpu_t *vcpu)

for (i = 7; i >= 0; i--) {
if (intr_pending[i]) {
offset = __fls(intr_pending[i]);
offset = asm_fls(intr_pending[i]);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ int hax_vm_set_ram(struct vm_t *vm, struct hax_set_ram_info *info)
hva = 0;
#endif
#endif
cur_va += page_size;
cur_va += HAX_PAGE_SIZE;
}

if (!hax_core_set_p2m(vm, gpfn, hpfn, hva, info->flags)) {
Expand Down
14 changes: 7 additions & 7 deletions core/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ static void vcpu_init(struct vcpu_t *vcpu)

vcpu->ref_count = 1;

vcpu->tsc_offset = 0ULL - rdtsc();
vcpu->tsc_offset = 0ULL - ia32_rdtsc();

// Prepare the vcpu state to Power-up
state->_rflags = 2;
Expand Down Expand Up @@ -3247,7 +3247,7 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)

switch (msr) {
case IA32_TSC: {
*val = vcpu->tsc_offset + rdtsc();
*val = vcpu->tsc_offset + ia32_rdtsc();
break;
}
case IA32_FEATURE_CONTROL: {
Expand Down Expand Up @@ -3503,7 +3503,7 @@ static int handle_msr_write(struct vcpu_t *vcpu, uint32_t msr, uint64_t val)

switch (msr) {
case IA32_TSC: {
vcpu->tsc_offset = val - rdtsc();
vcpu->tsc_offset = val - ia32_rdtsc();
if (vmx(vcpu, pcpu_ctls) & USE_TSC_OFFSETTING) {
vmwrite(vcpu, VMX_TSC_OFFSET, vcpu->tsc_offset);
}
Expand Down Expand Up @@ -4160,9 +4160,9 @@ int vcpu_pause(struct vcpu_t *vcpu)
return -1;

vcpu->paused = 1;
smp_mb();
hax_smp_mb();
if (vcpu->is_running) {
smp_call_function(&cpu_online_map, _vcpu_take_off, NULL);
hax_smp_call_function(&cpu_online_map, _vcpu_take_off, NULL);
}

return 0;
Expand All @@ -4171,15 +4171,15 @@ int vcpu_pause(struct vcpu_t *vcpu)
int vcpu_takeoff(struct vcpu_t *vcpu)
{
int cpu_id;
cpumap_t targets;
hax_cpumap_t targets;

// Don't change the sequence unless you are sure
if (vcpu->is_running) {
cpu_id = vcpu->cpu_id;
assert(cpu_id != hax_cpuid());
targets = cpu2cpumap(cpu_id);
// If not considering Windows XP, definitely we don't need this
smp_call_function(&targets, _vcpu_take_off, NULL);
hax_smp_call_function(&targets, _vcpu_take_off, NULL);
}

return 0;
Expand Down
50 changes: 50 additions & 0 deletions docs/manual-linux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## Building for Linux

**Disclaimer: Support for Linux is experimental.**

### Prerequisites
* Linux headers
* NASM 2.11 or later

### Build steps
1. `cd platforms/linux/`
1. `make`

## Testing on Linux
### System requirements
Note that these are requirements for the _test_ environment, which does not
have to be the same as the _build_ environment.

1. Hardware requirements are the same as those for Windows.
1. Linux 4.x or later.

### Loading and unloading the kernel module
To load the kernel module:
1. Make sure no other HAXM kernel module is loaded. If the output of
`lsmod | grep haxm` is not empty, you must unload the existing HAXM module
first: `sudo make uninstall`.
1. Run `sudo make install`.

To unload the kernel module:
1. Run `sudo make uninstall`.

Additionally, if you want to use HAXM as a non-privileged user,
you can enter the following command to make the current user
part of the *haxm* group (requires logging out and back in!):

```bash
sudo adduser `id -un` haxm
```

Note that in recent Linux distributions, you might get a `sign-file` error
since it kernel Makefiles will attempt to sign the kernel module with
`certs/signing_key.pem`. Unless driver signature enforcement has been enabled,
you can safely ignore this warning. Alternatively, you can follow
[this guide][linux-module-signing] to self-sign your drivers.

### Viewing logs
On Linux, HAXM debug output goes to the system log database, and can be
retrieved via `dmesg` (if supported, the `-w` flag will update the output).
You might filter these entries via: `dmesg | grep haxm`.

[linux-module-signing]: https://www.kernel.org/doc/html/v4.18/admin-guide/module-signing.html
10 changes: 10 additions & 0 deletions include/darwin/hax_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,14 @@ static inline bool cpu_is_online(int cpu)
return !!(((uint64_t)1 << cpu) & cpu_online_map);
}

#ifdef __cplusplus
extern "C" {
#endif

extern int cpu_number(void);

#ifdef __cplusplus
}
#endif

#endif // HAX_DARWIN_HAX_MAC_H_
8 changes: 4 additions & 4 deletions include/darwin/hax_types_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ static hax_atomic_t hax_atomic_dec(hax_atomic_t *address)

/*
* According to kernel programming, the Atomic function is barrier
* Although we can write a smp_mb from scrach, this simple one can resolve our
* Although we can write a hax_smp_mb from scrach, this simple one can resolve our
* issue
*/
static inline void smp_mb(void)
static inline void hax_smp_mb(void)
{
SInt32 atom;
OSAddAtomic(1, &atom);
Expand Down Expand Up @@ -132,10 +132,10 @@ typedef struct hax_kmap_phys {

typedef ulong mword;
typedef mword preempt_flag;
typedef uint64_t cpumap_t;
typedef uint64_t hax_cpumap_t;
typedef uint64_t HAX_VADDR_T;

static inline cpumap_t cpu2cpumap(int cpu)
static inline hax_cpumap_t cpu2cpumap(int cpu)
{
return (0x1UL << cpu);
}
Expand Down
13 changes: 7 additions & 6 deletions include/hax.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
// declaration
struct vcpu_t;

extern int hax_page_size;

#define HAX_CUR_VERSION 0x0004
#define HAX_COMPAT_VERSION 0x0001

Expand Down Expand Up @@ -207,7 +205,7 @@ void hax_set_page(phax_page page);

static inline uint64_t hax_page2pa(phax_page page)
{
return hax_page2pfn(page) << PAGE_SHIFT;
return hax_page2pfn(page) << HAX_PAGE_SHIFT;
}

#define hax_page_pa hax_page2pa
Expand All @@ -232,15 +230,15 @@ static inline unsigned char *hax_page_va(struct hax_page *page)
#define HAX_MAX_CPUS (sizeof(uint64_t) * 8)

/* Host SMP */
extern cpumap_t cpu_online_map;
extern hax_cpumap_t cpu_online_map;
extern int max_cpus;

#ifdef __cplusplus
extern "C" {
#endif

int smp_call_function(cpumap_t *cpus, void(*scfunc)(void *param), void *param);
extern int cpu_number(void);
int hax_smp_call_function(hax_cpumap_t *cpus, void(*scfunc)(void *param),
void *param);

uint32_t hax_cpuid(void);
int proc_event_pending(struct vcpu_t *vcpu);
Expand Down Expand Up @@ -268,6 +266,9 @@ int hax_em64t_enabled(void);
#ifdef HAX_PLATFORM_DARWIN
#include "darwin/hax_mac.h"
#endif
#ifdef HAX_PLATFORM_LINUX
#include "linux/hax_linux.h"
#endif
#ifdef HAX_PLATFORM_WINDOWS
#include "windows/hax_windows.h"
#endif
Expand Down
3 changes: 3 additions & 0 deletions include/hax_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
#ifdef HAX_PLATFORM_DARWIN
#include "darwin/hax_interface_mac.h"
#endif
#ifdef HAX_PLATFORM_LINUX
#include "linux/hax_interface_linux.h"
#endif
#ifdef HAX_PLATFORM_WINDOWS
#include "windows/hax_interface_windows.h"
#endif
Expand Down
Loading