#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../xen/xen.h"
/*
* The use of 'barrier' in the following reflects their use as local-lock
* operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
* critical operations are executed. All critical operatiosn must complete
* /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
* includes these barriers, for example.
*/
#define LOG(a)
extern shared_info_t *HYPERVISOR_shared_info;
void
xendie() {
panic("xendie called\n");
}
int
ipending(void) {
extern unsigned long upcallcount;
dp("ipending: @0x%llx mask 0x%ux, pending 0x%ux, pending_sel 0x%ux\n",
HYPERVISOR_shared_info->system_time,
HYPERVISOR_shared_info->evtchn_mask[0],
HYPERVISOR_shared_info->evtchn_pending[0],
HYPERVISOR_shared_info->evtchn_pending_sel);
dp("ipending: vcpu same 0x%ux, 0x%ux upcallcount 0x%lux\n",
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask,
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending,
upcallcount);
return HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending;
}
int XENCLI(void)
{
unsigned long s = islo();
// LOG(dp("XENCLI enter shared info is %p\n", HYPERVISOR_shared_info));
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
// LOG(dp("XENCLI done\n"));
// LOG(dp("splhi\n"));
return s;
}
int XENSTI(void)
{
void evtchn_do_upcall(Ureg *regs);
shared_info_t *_shared = HYPERVISOR_shared_info;
unsigned long realpfn(void *va);
int s = islo();
do {
_shared->vcpu_data[0].evtchn_upcall_mask = 0;
if (_shared->vcpu_data[0].evtchn_upcall_pending) {
LOG(dp("S\n"));
evtchn_do_upcall(0);
LOG(dp("s\n"));
}
} while (_shared->vcpu_data[0].evtchn_upcall_pending);
LOG(dp("SS%x\n", _shared->evtchn_mask[0]));
_shared->vcpu_data[0].evtchn_upcall_mask = 0;
/* dp("spllo _shared %p mask val 0x%lx pfn 0x%lx\n", _shared,
_shared->vcpu_data[0].evtchn_upcall_mask,
realpfn(_shared) );*/
return s;
}
unsigned long
getcr0() {
LOG(dp("GETCR0 ... return 0 ...\n"));
return 0;
}
unsigned long
getcr1() {
LOG(dp("GETCR1 ... return 0 ...\n"));
return 0;
}
unsigned long
getcr2() {
LOG(dp("GETCR2 ... return 0 ...\n"));
return 0;
}
/*
unsigned long
getcr3() {
LOG(dp("GETCR3 ... return 0 ...\n"));
return 0;
}
*/
unsigned long
getcr4() {
LOG(dp("GETCR4 ... return 0 ...\n"));
return 0;
}
void
putcr4() {
LOG(dp("putTCR4 ... NOOP ...\n"));
}
int islo(void) {
int retval;
shared_info_t *_shared = HYPERVISOR_shared_info;
retval = (_shared->vcpu_data[0].evtchn_upcall_mask == 0) ? 0x200 : 0;
return retval;
}
int
uartgetc(void) {
return -1;
}
void fpoff(void){
LOG(dp("fpoff. What to do?\n"));
}
void fpinit(void){
}
extern unsigned long *mfn;
/* this is called with the VIRTUAL address of the pdb */
void
putcr3(unsigned long *pnewcr3) { unsigned long *newcr3 = pnewcr3;
static unsigned long *prevcr3 = 0;
unsigned long realpfn;
LOG(dp("putcr3: cr3 %p\n", newcr3));
realpfn = mfn[PADDR(newcr3)>>PGSHIFT] << PGSHIFT;
LOG(dp("realpfn is 0x%ulx\n", realpfn));
USED(realpfn);
/* if it's the same one no need to pin it */
/* also, special case: first one was pinned */
if (prevcr3 && (newcr3 != prevcr3)) {
LOG(dp("INVAL %p, realpfn 0x%ulx\n", newcr3, realpfn));
/* HYPERVISOR_update_va_mapping(((unsigned long) newcr3)>>PGSHIFT,
(realpfn)|PTEVALID|PTERONLY, UVMF_INVLPG);
*/
LOG(dp("PIN %p\n", newcr3));
// queue_pgd_pin((ulong *)realpfn);
queue_pgd_pin(newcr3);
}
queue_pt_switch(PADDR(newcr3));
if (prevcr3 && (newcr3 != prevcr3)) {
LOG(dp("UNPIN 0x%ulx\n", prevcr3));
// queue_pgd_unpin((ulong *)(mfn[PADDR(prevcr3)>>PGSHIFT]<<PGSHIFT));
queue_pgd_unpin(prevcr3);
}
prevcr3 = newcr3;
LOG(dp("done q pt sw\n"));
queue_tlb_flush();
_flush_page_update_queue();
LOG(dp("done flush\n"));
}
#ifdef NOT_IN_GUEST
#define PROBLEM dp
int
inb(int port) {
PROBLEM("inb 0x%x\n", port);
return 0;
}
void
insb(int port, void *v, int count) {
PROBLEM("insb");
}
ushort
ins(int port) {
PROBLEM("ins");
return 0;
}
void
inss(int port, void *v, int count) {
PROBLEM("inss");
}
ulong
inl( int port) {
PROBLEM("inl");
return 0;
}
void
insl (int port, void *v, int count) {
PROBLEM("insl");
}
void
outb(int port, int byte) {
PROBLEM("outb 0x%x 0x%x\n", port, byte);
}
void
outsb(int port, void *v, int count) {
PROBLEM("outsb");
}
void
outs(int port, ushort s) {
PROBLEM("outs");
}
void
outss(int port, void *v, int count) {
PROBLEM("outss");
}
void
outl(int port, ulong l) {
PROBLEM("outl");
}
void
outsl(int port, void *v, int count) {
PROBLEM("outsl");
}
#endif
uvlong
xenmicroseconds(uvlong */*hz*/) {
dp("xenmicroseconds: current is 0x%ux\n",
HYPERVISOR_shared_info->wc_usec);
return HYPERVISOR_shared_info->wc_usec;
}
void halt(void) {
extern int nrdy;
LOG(dp("halt: nrdy %d, islo %d\n", nrdy, islo()));
if (nrdy)
return;
// spllo();
/* This is supposed to be HYPERVISOR_block().
* the reason is that with the yield, it just goes to
* other domains, and if they're not busy, comes right
* back to you. With block it does what you really want:
* blocks until interrupt. I've tested this and it works
* well, let me know if it is trouble. -- RGM
* HYPERVISOR_yield();
*/
HYPERVISOR_block();
}
#ifdef NOTYET
#define __save_flags(x)
do {
(x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask;
} while (0)
#define __restore_flags(x)
do {
shared_info_t *_shared = HYPERVISOR_shared_info;
barrier();
if ( (_shared->vcpu_data[0].evtchn_upcall_mask = x) == 0 ) {
barrier(); /* unmask then check (avoid races) */
if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) )
evtchn_do_upcall(NULL);
}
} while (0)
#define __save_and_cli(x)
do {
(x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask;
HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
barrier();
} while (0)
#define __save_and_sti(x)
do {
shared_info_t *_shared = HYPERVISOR_shared_info;
barrier();
(x) = _shared->vcpu_data[0].evtchn_upcall_mask;
_shared->vcpu_data[0].evtchn_upcall_mask = 0;
barrier(); /* unmask then check (avoid races) */
if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) )
evtchn_do_upcall(NULL);
} while (0)
#endif
|