#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]<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