[hyperv] Add support for Hyper-V hypervisor

Add support for detecting and communicating with the Hyper-V
hypervisor.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2014-12-11 17:22:18 +00:00
parent 1d2b7c91f7
commit d77a546fb4
10 changed files with 977 additions and 3 deletions

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/io.h>
#include <pic8259.h>
/** @file
*
* Minimal support for the 8259 Programmable Interrupt Controller
*
*/
/**
* Send non-specific EOI(s)
*
* @v irq IRQ number
*
* This seems to be inherently unsafe.
*/
static inline void send_nonspecific_eoi ( unsigned int irq ) {
DBG ( "Sending non-specific EOI for IRQ %d\n", irq );
if ( irq >= IRQ_PIC_CUTOFF ) {
outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR );
}
outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR );
}
/**
* Send specific EOI(s)
*
* @v irq IRQ number
*/
static inline void send_specific_eoi ( unsigned int irq ) {
DBG ( "Sending specific EOI for IRQ %d\n", irq );
if ( irq >= IRQ_PIC_CUTOFF ) {
outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( CHAINED_IRQ ) ),
ICR_REG ( CHAINED_IRQ ) );
}
outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( irq ) ), ICR_REG ( irq ) );
}
/**
* Send End-Of-Interrupt to the PIC
*
* @v irq IRQ number
*/
void send_eoi ( unsigned int irq ) {
send_specific_eoi ( irq );
}

View File

@@ -0,0 +1,72 @@
#ifndef _BITS_HYPERV_H
#define _BITS_HYPERV_H
/** @file
*
* Hyper-V interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include <stdint.h>
#include <ipxe/io.h>
/**
* Issue hypercall
*
* @v hv Hyper-V hypervisor
* @v code Call code
* @v in Input parameters
* @v out Output parameters
* @ret status Status code
*/
static inline __attribute__ (( always_inline )) int
hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
void *out ) {
void *hypercall = hv->hypercall;
uint32_t in_phys;
uint32_t out_phys;
uint32_t discard_ecx;
uint32_t discard_edx;
uint16_t result;
in_phys = ( ( __builtin_constant_p ( in ) && ( in == NULL ) )
? 0 : virt_to_phys ( in ) );
out_phys = ( ( __builtin_constant_p ( out ) && ( out == NULL ) )
? 0 : virt_to_phys ( out ) );
__asm__ __volatile__ ( "call *%9"
: "=a" ( result ), "=c" ( discard_ecx ),
"=d" ( discard_edx )
: "d" ( 0 ), "a" ( code ),
"b" ( 0 ), "c" ( in_phys ),
"D" ( 0 ), "S" ( out_phys ),
"m" ( hypercall ) );
return result;
}
/**
* Set bit atomically
*
* @v bits Bit field
* @v bit Bit to set
*/
static inline __attribute__ (( always_inline )) void
hv_set_bit ( void *bits, unsigned int bit ) {
struct {
uint32_t dword[ ( bit / 32 ) + 1 ];
} *dwords = bits;
/* Set bit using "lock bts". Inform compiler that any memory
* from the start of the bit field up to and including the
* dword containing this bit may be modified. (This is
* overkill but shouldn't matter in practice since we're
* unlikely to subsequently read other bits from the same bit
* field.)
*/
__asm__ __volatile__ ( "lock bts %1, %0"
: "+m" ( *dwords ) : "Ir" ( bit ) );
}
#endif /* _BITS_HYPERV_H */

View File

@@ -1,73 +0,0 @@
/*
* Basic support for controlling the 8259 Programmable Interrupt Controllers.
*
* Initially written by Michael Brown (mcb30).
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifndef PIC8259_H
#define PIC8259_H
#include <ipxe/io.h>
/* For segoff_t */
#include "realmode.h"
#define IRQ_PIC_CUTOFF 8
/* 8259 register locations */
#define PIC1_ICW1 0x20
#define PIC1_OCW2 0x20
#define PIC1_OCW3 0x20
#define PIC1_ICR 0x20
#define PIC1_IRR 0x20
#define PIC1_ISR 0x20
#define PIC1_ICW2 0x21
#define PIC1_ICW3 0x21
#define PIC1_ICW4 0x21
#define PIC1_IMR 0x21
#define PIC2_ICW1 0xa0
#define PIC2_OCW2 0xa0
#define PIC2_OCW3 0xa0
#define PIC2_ICR 0xa0
#define PIC2_IRR 0xa0
#define PIC2_ISR 0xa0
#define PIC2_ICW2 0xa1
#define PIC2_ICW3 0xa1
#define PIC2_ICW4 0xa1
#define PIC2_IMR 0xa1
/* Register command values */
#define OCW3_ID 0x08
#define OCW3_READ_IRR 0x03
#define OCW3_READ_ISR 0x02
#define ICR_EOI_NON_SPECIFIC 0x20
#define ICR_EOI_NOP 0x40
#define ICR_EOI_SPECIFIC 0x60
#define ICR_EOI_SET_PRIORITY 0xc0
/* Macros to enable/disable IRQs */
#define IMR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_IMR : PIC2_IMR )
#define IMR_BIT(x) ( 1 << ( (x) % IRQ_PIC_CUTOFF ) )
#define irq_enabled(x) ( ( inb ( IMR_REG(x) ) & IMR_BIT(x) ) == 0 )
#define enable_irq(x) outb ( inb( IMR_REG(x) ) & ~IMR_BIT(x), IMR_REG(x) )
#define disable_irq(x) outb ( inb( IMR_REG(x) ) | IMR_BIT(x), IMR_REG(x) )
/* Macros for acknowledging IRQs */
#define ICR_REG( irq ) ( (irq) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
#define ICR_VALUE( irq ) ( (irq) % IRQ_PIC_CUTOFF )
#define CHAINED_IRQ 2
/* Utility macros to convert IRQ numbers to INT numbers and INT vectors */
#define IRQ_INT( irq ) ( ( ( (irq) - IRQ_PIC_CUTOFF ) ^ 0x70 ) & 0x7f )
/* Other constants */
#define IRQ_MAX 15
#define IRQ_NONE -1U
/* Function prototypes
*/
void send_eoi ( unsigned int irq );
#endif /* PIC8259_H */