Merge branch 'master' into vmnet-tap

This commit is contained in:
xez 2015-07-06 21:44:34 -07:00
commit bd68d2b99c
15 changed files with 3186 additions and 68 deletions

View file

@ -1,3 +1,5 @@
GIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags)
ifeq ($V, 1)
VERBOSE =
else
@ -30,7 +32,7 @@ VMM_SRC := \
src/vmm/io/vrtc.c
XHYVE_SRC := \
src/acpi.c \
src/acpitbl.c \
src/atkbdc.c \
src/block_if.c \
src/consport.c \
@ -62,7 +64,8 @@ XHYVE_SRC := \
src/xmsr.c
FIRMWARE_SRC := \
src/firmware/kexec.c
src/firmware/kexec.c \
src/firmware/fbsd.c
SRC := \
$(VMM_SRC) \
@ -73,6 +76,8 @@ OBJ := $(SRC:src/%.c=build/%.o)
DEP := $(OBJ:%.o=%.d)
INC := -Iinclude
CFLAGS += -DVERSION=\"$(GIT_VERSION)\"
TARGET = build/xhyve
all: $(TARGET) | build

View file

@ -6,7 +6,7 @@
About
-----
The *xhyve hypervisor* is a port of [bhyve](http://www.bhyve.org) to OS X. It is built on top of Hypervisor.framework in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies. It can run vanilla Linux distributions and may gain support for other guest operating systems in the future.
The *xhyve hypervisor* is a port of [bhyve](http://www.bhyve.org) to OS X. It is built on top of Hypervisor.framework in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies. It can run FreeBSD and vanilla Linux distributions and may gain support for other guest operating systems in the future.
License: BSD
@ -180,31 +180,26 @@ TODO
----
- vmm:
- enable APIC access page to speed up APIC emulation
- enable x2APIC MSRs (even faster)
- enable APIC access page to speed up APIC emulation (**performance**)
- enable x2APIC MSRs (even faster) (**performance**)
- vmm_callout:
- is a quick'n'dirty implementation of the FreeBSD kernel callout mechanism
- seems to be racy
- fix races or perhaps replace with something better
- use per vCPU timer event thread (performance)?
- use per vCPU timer event thread (**performance**)?
- use hardware VMX preemption timer instead of `pthread_cond_wait` (**performance**)
- some 32-bit guests are broken (support PAE paging in VMCS)
- PCID guest support (performance)
- PCID guest support (**performance**)
- block_if:
- OS X does not support preadv/pwritev, we need to serialize reads and writes for the time being until we find a better solution. (performance)
- OS X does not support `preadv`/`pwritev`, we need to serialize reads and writes for the time being until we find a better solution. (**performance**)
- support block devices other than plain files
- virtio_net:
- unify TAP and vmnet backends
- vmnet: make it not require root
- vmnet: send/receive more than a single packet at a time (performance)
- ACPI tables don't work
- bhyve creates ASL on the fly and then calls out to an ASL compiler (iasl) on
every VM boot to create the DSDT:
- remove dependency on iasl by creating AML bytecode directly
- shouldn't be to hard since we we are only interested in a very small
subset of ASL
- vmnet: send/receive more than a single packet at a time (**performance**)
- virtio_rnd:
- is untested
- remove explicit state transitions:
- since only the owning task/thread can modify the VM/vCPUs a lot of the synchronization might be unnecessary
- since only the owning task/thread can modify the VM/vCPUs a lot of the synchronization might be unnecessary (**performance**)
- performance, performance and performance
- remove vestigial code, cleanup

View file

@ -30,6 +30,9 @@
#include <stdint.h>
/* if set, create AML instead of ASL and calling out to iasl */
#define ACPITBL_AML 1
#define SCI_INT 9
#define SMI_CMD 0xb2
@ -49,4 +52,6 @@ void dsdt_fixed_irq(uint8_t irq);
void dsdt_fixed_mem32(uint32_t base, uint32_t length);
void dsdt_indent(int levels);
void dsdt_unindent(int levels);
void dsdt_fixup(int bus, uint16_t iobase, uint16_t iolimit, uint32_t membase32,
uint32_t memlimit32, uint64_t membase64, uint64_t memlimit64);
void sci_init(void);

View file

@ -0,0 +1,102 @@
#pragma once
#include <stdint.h>
/*
* USERBOOT interface versions
*/
#define USERBOOT_VERSION_1 1
#define USERBOOT_VERSION_2 2
#define USERBOOT_VERSION_3 3
/*
* Exit codes from the loader
*/
#define USERBOOT_EXIT_QUIT 1
#define USERBOOT_EXIT_REBOOT 2
struct loader_callbacks {
/* Console i/o */
/* Wait until a key is pressed on the console and then return it */
int (*getc)(void *arg);
/* Write the character ch to the console */
void (*putc)(void *arg, int ch);
/* Return non-zero if a key can be read from the console */
int (*poll)(void *arg);
/* Host filesystem i/o */
/* Open a file in the host filesystem */
int (*open)(void *arg, const char *filename, void **h_return);
/* Close a file */
int (*close)(void *arg, void *h);
/* Return non-zero if the file is a directory */
int (*isdir)(void *arg, void *h);
/* Read size bytes from a file. The number of bytes remaining in dst after
* reading is returned in *resid_return
*/
int (*read)(void *arg, void *h, void *dst, size_t size,
size_t *resid_return);
/* Read an entry from a directory. The entry's inode number is returned in
* fileno_return, its type in *type_return and the name length in
* *namelen_return. The name itself is copied to the buffer name which must
* be at least PATH_MAX in size.
*/
int (*readdir)(void *arg, void *h, uint32_t *fileno_return,
uint8_t *type_return, size_t *namelen_return, char *name);
/* Seek to a location within an open file */
int (*seek)(void *arg, void *h, uint64_t offset, int whence);
/* Return some stat(2) related information about the file */
int (*stat)(void *arg, void *h, int *mode_return, int *uid_return,
int *gid_return, uint64_t *size_return);
/* Disk image i/o */
/* Read from a disk image at the given offset */
int (*diskread)(void *arg, int unit, uint64_t offset, void *dst,
size_t size, size_t *resid_return);
/* Guest virtual machine i/o */
/* Copy to the guest address space */
int (*copyin)(void *arg, const void *from, uint64_t to, size_t size);
/* Copy from the guest address space */
int (*copyout)(void *arg, uint64_t from, void *to, size_t size);
/* Set a guest register value */
void (*setreg)(void *arg, int, uint64_t);
/* Set a guest MSR value */
void (*setmsr)(void *arg, int, uint64_t);
/* Set a guest CR value */
void (*setcr)(void *arg, int, uint64_t);
/* Set the guest GDT address */
void (*setgdt)(void *arg, uint64_t, size_t);
/* Transfer control to the guest at the given address */
void (*exec)(void *arg, uint64_t pc);
/* Misc */
/* Sleep for usec microseconds */
void (*delay)(void *arg, int usec);
/* Exit with the given exit code */
void (*exit)(void);
/* Return guest physical memory map details */
void (*getmem)(void *arg, uint64_t *lowmem, uint64_t *highmem);
/* ioctl interface to the disk device */
int (*diskioctl)(void *arg, int unit, u_long cmd, void *data);
/*
* Returns an environment variable in the form "name=value".
*
* If there are no more variables that need to be set in the
* loader environment then return NULL.
*
* 'num' is used as a handle for the callback to identify which
* environment variable to return next. It will begin at 0 and
* each invocation will add 1 to the previous value of 'num'.
*/
const char * (*getenv)(void *arg, int num);
};
void fbsd_init(char *userboot_path, char *bootvolume_path, char *kernelenv,
char *cons);
uint64_t fbsd_load(void);

View file

@ -54,23 +54,26 @@
#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */
#define GSEL(s,r) (((s)<<3) | r) /* a global selector */
// /*
// * User segment descriptors (%cs, %ds etc for i386 apps. 64 bit wide)
// * For long-mode apps, %cs only has the conforming bit in sd_type, the sd_dpl,
// * sd_p, sd_l and sd_def32 which must be zero). %ds only has sd_p.
// */
// struct segment_descriptor {
// unsigned sd_lolimit:16; /* segment extent (lsb) */
// unsigned sd_lobase:24; /* segment base address (lsb) */
// unsigned sd_type:5; /* segment type */
// unsigned sd_dpl:2; /* segment descriptor priority level */
// unsigned sd_p:1; /* segment descriptor present */
// unsigned sd_hilimit:4; /* segment extent (msb) */
// unsigned sd_xx:2; /* unused */
// unsigned sd_def32:1; /* default 32 vs 16 bit size */
// unsigned sd_gran:1; /* limit granularity (byte/page units)*/
// unsigned sd_hibase:8; /* segment base address (msb) */
// } __packed;
/*
* User segment descriptors (%cs, %ds etc for i386 apps. 64 bit wide)
* For long-mode apps, %cs only has the conforming bit in sd_type, the sd_dpl,
* sd_p, sd_l and sd_def32 which must be zero). %ds only has sd_p.
*/
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpacked"
struct segment_descriptor {
unsigned sd_lolimit:16; /* segment extent (lsb) */
unsigned sd_lobase:24; /* segment base address (lsb) */
unsigned sd_type:5; /* segment type */
unsigned sd_dpl:2; /* segment descriptor priority level */
unsigned sd_p:1; /* segment descriptor present */
unsigned sd_hilimit:4; /* segment extent (msb) */
unsigned sd_xx:2; /* unused */
unsigned sd_def32:1; /* default 32 vs 16 bit size */
unsigned sd_gran:1; /* limit granularity (byte/page units)*/
unsigned sd_hibase:8; /* segment base address (msb) */
} __packed;
#pragma clang diagnostic pop
struct user_segment_descriptor {
uint64_t sd_lolimit:16; /* segment extent (lsb) */
@ -167,16 +170,16 @@ struct user_segment_descriptor {
// /* memory segment types */
// #define SDT_MEMRO 16 memory read only
// #define SDT_MEMROA 17 /* memory read only accessed */
// #define SDT_MEMRW 18 /* memory read write */
// #define SDT_MEMRWA 19 /* memory read write accessed */
#define SDT_MEMRW 18 /* memory read write */
#define SDT_MEMRWA 19 /* memory read write accessed */
// #define SDT_MEMROD 20 /* memory read only expand dwn limit */
// #define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
// #define SDT_MEMRWD 22 /* memory read write expand dwn limit */
// #define SDT_MEMRWDA 23 /* memory read write expand dwn limit accessed*/
// #define SDT_MEME 24 /* memory execute only */
// #define SDT_MEMEA 25 /* memory execute only accessed */
// #define SDT_MEMER 26 /* memory execute read */
// #define SDT_MEMERA 27 /* memory execute read accessed */
#define SDT_MEMER 26 /* memory execute read */
#define SDT_MEMERA 27 /* memory execute read accessed */
// #define SDT_MEMEC 28 /* memory execute only conforming */
// #define SDT_MEMEAC 29 /* memory execute only accessed conforming */
// #define SDT_MEMERC 30 /* memory execute read conforming */

View file

@ -93,7 +93,7 @@ void vmm_stat_free(void *vp);
* 'buf' should be at least fit 'MAX_VMM_STAT_TYPES' entries
*/
int vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf);
int vmm_stat_desc_copy(int index, char *buf, int buflen);
int vmm_stat_desc_copy(int index, char *buf, size_t buflen);
static void __inline
vmm_stat_array_incr(struct vm *vm, int vcpu, struct vmm_stat_type *vst,

1076
src/acpitbl.c Normal file

File diff suppressed because it is too large Load diff

841
src/dsdt.asl Normal file
View file

@ -0,0 +1,841 @@
/*
* bhyve DSDT template
*/
DefinitionBlock ("bhyve_dsdt.aml", "DSDT", 2,"BHYVE ", "BVDSDT ", 0x00000001)
{
Name (_S5, Package ()
{
0x05,
Zero,
})
Name (PICM, 0x00)
Method (_PIC, 1, NotSerialized)
{
Store (Arg0, PICM)
}
Scope (_SB)
{
Device (PC00)
{
Name (_HID, EisaId ("PNP0A03"))
Name (_ADR, Zero)
Method (_BBN, 0, NotSerialized)
{
Return (0x00000000)
}
Name (_CRS, ResourceTemplate ()
{
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
0x0000, // Granularity
0x0000, // Range Minimum
0x0000, // Range Maximum
0x0000, // Translation Offset
0x0001, // Length
,, )
IO (Decode16,
0x0CF8, // Range Minimum
0x0CF8, // Range Maximum
0x01, // Alignment
0x08, // Length
)
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, // Granularity
0x0000, // Range Minimum
0x0CF7, // Range Maximum
0x0000, // Translation Offset
0x0CF8, // Length
,, , TypeStatic)
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, // Granularity
0x0D00, // Range Minimum
0x1FFF, // Range Maximum
0x0000, // Translation Offset
0x1300, // Length
,, , TypeStatic)
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, // Granularity
0x0000, // Range Minimum
0x0000, // Range Maximum
0x0000, // Translation Offset
0x0020, // Length
,, , TypeStatic)
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
0x00000000, // Granularity
0x00000000, // Range Minimum
0x00000000, // Range Maximum
0x00000000, // Translation Offset
0x00000000, // Length
,, , AddressRangeMemory, TypeStatic)
QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
0x0000000000000000, // Granularity
0x0000000000000000, // Range Minimum
0x0000000000000000, // Range Maximum
0x0000000000000000, // Translation Offset
0x0000000000000000, // Length
,, , AddressRangeMemory, TypeStatic)
})
Name (PPRT, Package ()
{
Package ()
{
0x1FFFF,
0x00,
\_SB.PC00.ISA.LNKA,,
0x00
},
Package ()
{
0x2FFFF,
0x00,
\_SB.PC00.ISA.LNKB,,
0x00
},
Package ()
{
0x3FFFF,
0x00,
\_SB.PC00.ISA.LNKC,,
0x00
},
Package ()
{
0x4FFFF,
0x00,
\_SB.PC00.ISA.LNKD,,
0x00
},
Package ()
{
0x5FFFF,
0x00,
\_SB.PC00.ISA.LNKE,,
0x00
},
Package ()
{
0x6FFFF,
0x00,
\_SB.PC00.ISA.LNKF,,
0x00
},
Package ()
{
0x7FFFF,
0x00,
\_SB.PC00.ISA.LNKG,,
0x00
},
Package ()
{
0x8FFFF,
0x00,
\_SB.PC00.ISA.LNKH,,
0x00
},
})
Name (APRT, Package ()
{
Package ()
{
0x1FFFF,
0x00,
Zero,
0x10
},
Package ()
{
0x2FFFF,
0x00,
Zero,
0x11
},
Package ()
{
0x3FFFF,
0x00,
Zero,
0x12
},
Package ()
{
0x4FFFF,
0x00,
Zero,
0x13
},
Package ()
{
0x5FFFF,
0x00,
Zero,
0x14
},
Package ()
{
0x6FFFF,
0x00,
Zero,
0x15
},
Package ()
{
0x7FFFF,
0x00,
Zero,
0x16
},
Package ()
{
0x8FFFF,
0x00,
Zero,
0x17
},
})
Method (_PRT, 0, NotSerialized)
{
If (PICM)
{
Return (APRT)
}
Else
{
Return (PPRT)
}
}
Device (ISA)
{
Name (_ADR, 0x001F0000)
OperationRegion (LPCR, PCI_Config, 0x00, 0x100)
Field (LPCR, AnyAcc, NoLock, Preserve)
{
Offset (0x60),
PIRA, 8,
PIRB, 8,
PIRC, 8,
PIRD, 8,
Offset (0x68),
PIRE, 8,
PIRF, 8,
PIRG, 8,
PIRH, 8
}
Method (PIRV, 1, NotSerialized)
{
If (And (Arg0, 0x80))
{
Return (0x00)
}
And (Arg0, 0x0F, Local0)
If (LLess (Local0, 0x03))
{
Return (0x00)
}
If (LEqual (Local0, 0x08))
{
Return (0x00)
}
If (LEqual (Local0, 0x0D))
{
Return (0x00)
}
Return (0x01)
}
Device (LNKA)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x01)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRA))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB01, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB01, 0x01, CIRA)
Method (_CRS, 0, NotSerialized)
{
And (PIRA, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRA)
}
Else
{
Store (0x00, CIRA)
}
Return (CB01)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRA)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRA)
FindSetRightBit (SIRA, Local0)
Store (Decrement (Local0), PIRA)
}
}
Device (LNKB)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x02)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRB))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB02, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB02, 0x01, CIRB)
Method (_CRS, 0, NotSerialized)
{
And (PIRB, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRB)
}
Else
{
Store (0x00, CIRB)
}
Return (CB02)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRB)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRB)
FindSetRightBit (SIRB, Local0)
Store (Decrement (Local0), PIRB)
}
}
Device (LNKC)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x03)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRC))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB03, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB03, 0x01, CIRC)
Method (_CRS, 0, NotSerialized)
{
And (PIRC, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRC)
}
Else
{
Store (0x00, CIRC)
}
Return (CB03)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRC)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRC)
FindSetRightBit (SIRC, Local0)
Store (Decrement (Local0), PIRC)
}
}
Device (LNKD)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x04)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRD))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB04, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB04, 0x01, CIRD)
Method (_CRS, 0, NotSerialized)
{
And (PIRD, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRD)
}
Else
{
Store (0x00, CIRD)
}
Return (CB04)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRD)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRD)
FindSetRightBit (SIRD, Local0)
Store (Decrement (Local0), PIRD)
}
}
Device (LNKE)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x05)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRE))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB05, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB05, 0x01, CIRE)
Method (_CRS, 0, NotSerialized)
{
And (PIRE, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRE)
}
Else
{
Store (0x00, CIRE)
}
Return (CB05)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRE)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRE)
FindSetRightBit (SIRE, Local0)
Store (Decrement (Local0), PIRE)
}
}
Device (LNKF)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x06)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRF))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB06, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB06, 0x01, CIRF)
Method (_CRS, 0, NotSerialized)
{
And (PIRF, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRF)
}
Else
{
Store (0x00, CIRF)
}
Return (CB06)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRF)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRF)
FindSetRightBit (SIRF, Local0)
Store (Decrement (Local0), PIRF)
}
}
Device (LNKG)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x07)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRG))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB07, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB07, 0x01, CIRG)
Method (_CRS, 0, NotSerialized)
{
And (PIRG, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRG)
}
Else
{
Store (0x00, CIRG)
}
Return (CB07)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRG)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRG)
FindSetRightBit (SIRG, Local0)
Store (Decrement (Local0), PIRG)
}
}
Device (LNKH)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x08)
Method (_STA, 0, NotSerialized)
{
If (PIRV (PIRH))
{
Return (0x0B)
}
Else
{
Return (0x09)
}
}
Name (_PRS, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{3,4,5,6,7,9,10,11,12,14,15}
})
Name (CB08, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared, )
{}
})
CreateWordField (CB08, 0x01, CIRH)
Method (_CRS, 0, NotSerialized)
{
And (PIRH, 0x8F, Local0)
If (PIRV (Local0))
{
ShiftLeft (0x01, Local0, CIRH)
}
Else
{
Store (0x00, CIRH)
}
Return (CB08)
}
Method (_DIS, 0, NotSerialized)
{
Store (0x80, PIRH)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, SIRH)
FindSetRightBit (SIRH, Local0)
Store (Decrement (Local0), PIRH)
}
}
Device (SIO)
{
Name (_HID, EisaId ("PNP0C02"))
Name (_CRS, ResourceTemplate ()
{
IO (Decode16,
0x0060, // Range Minimum
0x0060, // Range Maximum
0x01, // Alignment
0x01, // Length
)
IO (Decode16,
0x0064, // Range Minimum
0x0064, // Range Maximum
0x01, // Alignment
0x01, // Length
)
IO (Decode16,
0x0220, // Range Minimum
0x0220, // Range Maximum
0x01, // Alignment
0x04, // Length
)
IO (Decode16,
0x0224, // Range Minimum
0x0224, // Range Maximum
0x01, // Alignment
0x04, // Length
)
Memory32Fixed (ReadWrite,
0xE0000000, // Address Base
0x10000000, // Address Length
)
IO (Decode16,
0x04D0, // Range Minimum
0x04D0, // Range Maximum
0x01, // Alignment
0x02, // Length
)
IO (Decode16,
0x0061, // Range Minimum
0x0061, // Range Maximum
0x01, // Alignment
0x01, // Length
)
IO (Decode16,
0x0400, // Range Minimum
0x0400, // Range Maximum
0x01, // Alignment
0x08, // Length
)
IO (Decode16,
0x00B2, // Range Minimum
0x00B2, // Range Maximum
0x01, // Alignment
0x01, // Length
)
IO (Decode16,
0x0084, // Range Minimum
0x0084, // Range Maximum
0x01, // Alignment
0x01, // Length
)
IO (Decode16,
0x0072, // Range Minimum
0x0072, // Range Maximum
0x01, // Alignment
0x06, // Length
)
})
}
Device (COM1)
{
Name (_HID, EisaId ("PNP0501"))
Name (_UID, 1)
Name (_CRS, ResourceTemplate ()
{
IO (Decode16,
0x03F8, // Range Minimum
0x03F8, // Range Maximum
0x01, // Alignment
0x08, // Length
)
IRQNoFlags ()
{4}
})
}
Device (COM2)
{
Name (_HID, EisaId ("PNP0501"))
Name (_UID, 2)
Name (_CRS, ResourceTemplate ()
{
IO (Decode16,
0x02F8, // Range Minimum
0x02F8, // Range Maximum
0x01, // Alignment
0x08, // Length
)
IRQNoFlags ()
{3}
})
}
Device (RTC)
{
Name (_HID, EisaId ("PNP0B00"))
Name (_CRS, ResourceTemplate ()
{
IO (Decode16,
0x0070, // Range Minimum
0x0070, // Range Maximum
0x01, // Alignment
0x02, // Length
)
IRQNoFlags ()
{8}
})
}
Device (PIC)
{
Name (_HID, EisaId ("PNP0000"))
Name (_CRS, ResourceTemplate ()
{
IO (Decode16,
0x0020, // Range Minimum
0x0020, // Range Maximum
0x01, // Alignment
0x02, // Length
)
IO (Decode16,
0x00A0, // Range Minimum
0x00A0, // Range Maximum
0x01, // Alignment
0x02, // Length
)
IRQNoFlags ()
{2}
})
}
Device (TIMR)
{
Name (_HID, EisaId ("PNP0100"))
Name (_CRS, ResourceTemplate ()
{
IO (Decode16,
0x0040, // Range Minimum
0x0040, // Range Maximum
0x01, // Alignment
0x04, // Length
)
IRQNoFlags ()
{0}
})
}
}
}
}
Scope (_SB.PC00)
{
Device (HPET)
{
Name (_HID, EISAID("PNP0103"))
Name (_UID, 0)
Name (_CRS, ResourceTemplate ()
{
Memory32Fixed (ReadWrite,
0xFED00000, // Address Base
0x00000400, // Address Length
)
})
}
}
}

1006
src/firmware/fbsd.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1217,6 +1217,32 @@ pci_pirq_prt_entry(UNUSED int bus, int slot, int pin, int pirq_pin,
* A bhyve virtual machine has a flat PCI hierarchy with a root port
* corresponding to each PCI bus.
*/
#if ACPITBL_AML
static void
pci_bus_write_dsdt(int bus)
{
struct businfo *bi;
/*
* If there are no devices on this 'bus' then just return.
*/
if ((bi = pci_businfo[bus]) == NULL) {
/*
* Bus 0 is special because it decodes the I/O ports used
* for PCI config space access even if there are no devices
* on it.
*/
if (bus != 0)
return;
}
dsdt_fixup(bus, bi->iobase, bi->iolimit, bi->membase32, bi->memlimit32,
bi->membase64, bi->memlimit64);
(void) pci_pirq_prt_entry;
(void) pci_apic_prt_entry;
}
#else
static void
pci_bus_write_dsdt(int bus)
{
@ -1365,7 +1391,19 @@ pci_bus_write_dsdt(int bus)
done:
dsdt_line(" }");
}
#endif
#if ACPITBL_AML
void
pci_write_dsdt(void)
{
int bus;
for (bus = 0; bus < MAXBUSES; bus++) {
pci_bus_write_dsdt(bus);
}
}
#else
void
pci_write_dsdt(void)
{
@ -1385,6 +1423,7 @@ pci_write_dsdt(void)
dsdt_line("}");
dsdt_unindent(1);
}
#endif
int
pci_bus_configured(int bus)

View file

@ -112,7 +112,7 @@ vmm_stat_free(void *vp)
}
int
vmm_stat_desc_copy(int index, char *buf, int bufsize)
vmm_stat_desc_copy(int index, char *buf, size_t bufsize)
{
int i;
struct vmm_stat_type *vst;

View file

@ -66,6 +66,7 @@
#include <xhyve/rtc.h>
#include <xhyve/firmware/kexec.h>
#include <xhyve/firmware/fbsd.h>
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
@ -112,10 +113,12 @@ static struct bhyvestats {
#pragma clang diagnostic ignored "-Wpadded"
static struct mt_vmm_info {
pthread_t mt_thr;
int mt_vcpu;
int mt_vcpu;
} mt_vmm_info[VM_MAXCPU];
#pragma clang diagnostic pop
static uint64_t (*fw_func)(void);
__attribute__ ((noreturn)) static void
usage(int code)
{
@ -138,6 +141,7 @@ usage(int code)
" -s: <slot,driver,configinfo> PCI slot config\n"
" -u: RTC keeps UTC time\n"
" -U: uuid\n"
" -v: show build version\n"
" -w: ignore unimplemented MSRs\n"
" -W: force virtio to use single-vector MSI\n"
" -x: local apic is in x2APIC mode\n"
@ -147,6 +151,17 @@ usage(int code)
exit(code);
}
__attribute__ ((noreturn)) static void
show_version()
{
fprintf(stderr, "%s: %s\n\n%s\n",progname, VERSION,
"xhyve is a port of FreeBSD's bhyve hypervisor to OS X that\n"
"works entirely in userspace and has no other dependencies.\n\n"
"Homepage: https://github.com/mist64/xhyve\n"
"License: BSD\n");
exit(0);
}
void
xh_vm_inject_fault(int vcpu, int vector, int errcode_valid,
uint32_t errcode)
@ -237,7 +252,7 @@ vcpu_thread(void *param)
assert(error == 0);
if (vcpu == BSP) {
rip_entry = kexec();
rip_entry = fw_func();
} else {
rip_entry = vmexit[vcpu].rip;
spinup_ap_realmode(vcpu, &rip_entry);
@ -703,45 +718,57 @@ parse_memsize(const char *opt, size_t *ret_memsize)
static int
firmware_parse(const char *opt) {
char *fw, *kernel, *initrd, *cmdline, *cp;
char *fw, *opt1, *opt2, *opt3, *cp;
fw = strdup(opt);
if (strncmp(fw, "kexec", strlen("kexec")) != 0) {
goto fail;
}
if ((cp = strchr(fw, ',')) != NULL) {
*cp = '\0';
kernel = cp + 1;
if (strncmp(fw, "kexec", strlen("kexec")) == 0) {
fw_func = kexec;
} else if (strncmp(fw, "fbsd", strlen("fbsd")) == 0) {
fw_func = fbsd_load;
} else {
goto fail;
}
if ((cp = strchr(kernel, ',')) != NULL) {
*cp = '\0';
initrd = cp + 1;
if ((cp = strchr(fw, ',')) != NULL) {
*cp = '\0';
opt1 = cp + 1;
} else {
goto fail;
}
if ((cp = strchr(opt1, ',')) != NULL) {
*cp = '\0';
opt2 = cp + 1;
} else {
goto fail;
}
if ((cp = strchr(opt2, ',')) != NULL) {
*cp = '\0';
opt3 = cp + 1;
} else {
goto fail;
}
opt2 = strlen(opt2) ? opt2 : NULL;
opt3 = strlen(opt3) ? opt3 : NULL;
if (fw_func == kexec) {
kexec_init(opt1, opt2, opt3);
} else if (fw_func == fbsd_load) {
/* FIXME: let user set boot-loader serial device */
fbsd_init(opt1, opt2, opt3, NULL);
} else {
goto fail;
}
if ((cp = strchr(initrd, ',')) != NULL) {
*cp = '\0';
cmdline = cp + 1;
} else {
goto fail;
}
initrd = strlen(initrd) ? initrd : NULL;
cmdline = strlen(cmdline) ? cmdline : NULL;
kexec_init(kernel, initrd, cmdline);
return 0;
fail:
fprintf(stderr, "Invalid firmare argument\n"
" -f kexec,'kernel','initrd','\"cmdline\"'\n");
" -f kexec,'kernel','initrd','\"cmdline\"'\n"
" -f fbsd,'userboot','boot volume','\"kernel env\"'\n");
return -1;
}
@ -765,7 +792,7 @@ main(int argc, char *argv[])
rtc_localtime = 1;
fw = 0;
while ((c = getopt(argc, argv, "behuwxACHPWY:f:g:c:s:m:l:U:")) != -1) {
while ((c = getopt(argc, argv, "behvuwxACHPWY:f:g:c:s:m:l:U:")) != -1) {
switch (c) {
case 'A':
acpi = 1;
@ -832,8 +859,10 @@ main(int argc, char *argv[])
case 'Y':
mptgen = 0;
break;
case 'v':
show_version();
case 'h':
usage(0);
usage(0);
default:
usage(1);
}
@ -908,7 +937,6 @@ main(int argc, char *argv[])
error = acpi_build(guest_ncpus);
assert(error == 0);
}
rip = 0;

BIN
test/userboot.so Executable file

Binary file not shown.

8
test/userboot.txt Normal file
View file

@ -0,0 +1,8 @@
userboot.so is the FreeBSD user-mode bootloader
So, this is a bit horrible but it works:
- userboot is compiled on FreeBSD with '-target x86_64-apple-darwin14' CFLAGS
- same for the dependencies of userboot (stand, ficl, zfs)
- you have to use the MachO linker set header (include/xhyve/support/linker_set.h)
- the resulting object files are linked on OS X with 'clang -dead_strip -shared -o userboot.so *.o *.So'

View file

@ -1,9 +1,15 @@
#!/bin/sh
# Linux
KERNEL="test/vmlinuz"
INITRD="test/initrd.gz"
CMDLINE="earlyprintk=serial console=ttyS0 acpi=off"
# FreeBSD
#USERBOOT="test/userboot.so"
#BOOTVOLUME="/somepath/somefile.{img | iso}"
#KERNELENV=""
MEM="-m 1G"
#SMP="-c 2"
#NET="-s 2:0,virtio-net"
@ -13,4 +19,8 @@ PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
LPC_DEV="-l com1,stdio"
#UUID="-U deadbeef-dead-dead-dead-deaddeafbeef"
# Linux
build/xhyve $MEM $SMP $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD $UUID -f kexec,$KERNEL,$INITRD,"$CMDLINE"
# FreeBSD
#build/xhyve -A $MEM $SMP $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD $UUID -f fbsd,$USERBOOT,$BOOTVOLUME,"$KERNELENV"