int c0_compare_int_usable(void) { unsigned int delta; unsigned int cnt; #ifdef CONFIG_KVM_GUEST return 1; #endif /* * IP7 already pending? Try to clear it by acking the timer. */ if (c0_compare_int_pending()) { cnt = read_c0_count(); write_c0_compare(cnt); back_to_back_c0_hazard(); while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) if (!c0_compare_int_pending()) break; if (c0_compare_int_pending()) return 0; } for (delta = 0x10; delta <= 0x400000; delta <<= 1) { cnt = read_c0_count(); cnt += delta; write_c0_compare(cnt); back_to_back_c0_hazard(); if ((int)(read_c0_count() - cnt) < 0) break; /* increase delta if the timer was already expired */ } while ((int)(read_c0_count() - cnt) <= 0) ; /* Wait for expiry */ while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) if (c0_compare_int_pending()) break; if (!c0_compare_int_pending()) return 0; cnt = read_c0_count(); write_c0_compare(cnt); back_to_back_c0_hazard(); while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) if (!c0_compare_int_pending()) break; if (c0_compare_int_pending()) return 0; /* * Feels like a real count / compare timer. */ return 1; }
int c0_compare_int_usable(void) { unsigned int delta; unsigned int cnt; /* */ if (c0_compare_int_pending()) { cnt = read_c0_count(); write_c0_compare(cnt); back_to_back_c0_hazard(); while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) if (!c0_compare_int_pending()) break; if (c0_compare_int_pending()) return 0; } for (delta = 0x10; delta <= 0x400000; delta <<= 1) { cnt = read_c0_count(); cnt += delta; write_c0_compare(cnt); back_to_back_c0_hazard(); if ((int)(read_c0_count() - cnt) < 0) break; /* */ } while ((int)(read_c0_count() - cnt) <= 0) ; /* */ while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) if (c0_compare_int_pending()) break; if (!c0_compare_int_pending()) return 0; cnt = read_c0_count(); write_c0_compare(cnt); back_to_back_c0_hazard(); while (read_c0_count() < (cnt + COMPARE_INT_SEEN_TICKS)) if (!c0_compare_int_pending()) break; if (c0_compare_int_pending()) return 0; /* */ return 1; }
static void mips_cpu_irq_disable(unsigned int irq) { unsigned long flags; local_irq_save(flags); mask_mips_irq(irq); back_to_back_c0_hazard(); local_irq_restore(flags); }
IMPLEMENTATION [mips32]: #include <cstring> #include "mipsregs.h" #include "panic.h" #include "warn.h" PRIVATE static void Utcb_init::validate_utcb() { const Mword dummy = 0x12345678; Mword old_value = 0; Mword new_value = 0; // TODO may need to expand validate_utcb() to catch an exception but this // approach is sufficient for platforms which silently ignore the accesses. // Write the test such that the exception handler can skip the faulting access // and still detect a failure, or consider using _recover_jmpbuf. if ((int)Config::Warn_level >= Warning) printf("Verifying access to UTCB pointer... "); // Detect issues with accessing the UTCB pointer early on. old_value = read_c0_ddatalo(); write_c0_ddatalo(dummy); back_to_back_c0_hazard(); new_value = read_c0_ddatalo(); write_c0_ddatalo(old_value); if (dummy != new_value) panic("UTCB pointer could not be stored in DDataLo register.\n" "Consider using another COP0 register available to your platform.\n"); else if ((int)Config::Warn_level >= Warning) printf("UTCB pointer stored in DDataLo\n"); } // XXXKYMA: Store the UTCB pointer in COP0-DDataLo Register. // This can be set in kernel mode and read in user mode. IMPLEMENT void Utcb_init::init() { validate_utcb(); }