示例#1
0
zx_status_t platform_set_oneshot_timer(zx_time_t deadline) {
    DEBUG_ASSERT(arch_ints_disabled());

    if (deadline < 0) {
        deadline = 0;
    }
    deadline = discrete_time_roundup(deadline);
    DEBUG_ASSERT(deadline > 0);

    if (use_tsc_deadline) {
        // Check if the deadline would overflow the TSC.
        const uint64_t tsc_ticks_per_ns = tsc_ticks_per_ms / ZX_MSEC(1);
        if (UINT64_MAX / deadline < tsc_ticks_per_ns) {
            return ZX_ERR_INVALID_ARGS;
        }

        // We rounded up to the tick after above.
        const uint64_t tsc_deadline = u64_mul_u64_fp32_64(deadline, tsc_per_ns);
        LTRACEF("Scheduling oneshot timer: %" PRIu64 " deadline\n", tsc_deadline);
        apic_timer_set_tsc_deadline(tsc_deadline, false /* unmasked */);
        return ZX_OK;
    }

    const zx_time_t now = current_time();
    if (now >= deadline) {
        // Deadline has already passed. We still need to schedule a timer so that
        // the interrupt fires.
        LTRACEF("Scheduling oneshot timer for min duration\n");
        return apic_timer_set_oneshot(1, 1, false /* unmasked */);
    }
    const zx_duration_t interval = zx_time_sub_time(deadline, now);
    DEBUG_ASSERT(interval > 0);

    uint64_t apic_ticks_needed = u64_mul_u64_fp32_64(interval, apic_ticks_per_ns);
    if (apic_ticks_needed == 0) {
        apic_ticks_needed = 1;
    }

    // Find the shift needed for this timeout, since count is 32-bit.
    const uint highest_set_bit = log2_ulong_floor(apic_ticks_needed);
    uint8_t extra_shift = (highest_set_bit <= 31) ? 0 : static_cast<uint8_t>(highest_set_bit - 31);
    if (extra_shift > 8) {
        extra_shift = 8;
    }

    uint32_t divisor = apic_divisor << extra_shift;
    uint32_t count;
    // If the divisor is too large, we're at our maximum timeout.  Saturate the
    // timer.  It'll fire earlier than requested, but the scheduler will notice
    // and ask us to set the timer up again.
    if (divisor <= 128) {
        count = (uint32_t)(apic_ticks_needed >> extra_shift);
        DEBUG_ASSERT((apic_ticks_needed >> extra_shift) <= UINT32_MAX);
    } else {
示例#2
0
static void spinlock_test(void)
{
    spin_lock_saved_state_t state;
    spin_lock_t lock;

    spin_lock_init(&lock);

    // verify basic functionality (single core)
    printf("testing spinlock:\n");
    ASSERT(!spin_lock_held(&lock));
    ASSERT(!arch_ints_disabled());
    spin_lock_irqsave(&lock, state);
    ASSERT(arch_ints_disabled());
    ASSERT(spin_lock_held(&lock));
    spin_unlock_irqrestore(&lock, state);
    ASSERT(!spin_lock_held(&lock));
    ASSERT(!arch_ints_disabled());
    printf("seems to work\n");

#define COUNT (1024*1024)
    uint32_t c = arch_cycle_count();
    for (uint i = 0; i < COUNT; i++) {
        spin_lock(&lock);
        spin_unlock(&lock);
    }
    c = arch_cycle_count() - c;

    printf("%u cycles to acquire/release lock %u times (%u cycles per)\n", c, COUNT, c / COUNT);

    c = arch_cycle_count();
    for (uint i = 0; i < COUNT; i++) {
        spin_lock_irqsave(&lock, state);
        spin_unlock_irqrestore(&lock, state);
    }
    c = arch_cycle_count() - c;

    printf("%u cycles to acquire/release lock w/irqsave %u times (%u cycles per)\n", c, COUNT, c / COUNT);
#undef COUNT
}
示例#3
0
static void calibrate_tsc(bool has_pvclock) {
    ASSERT(arch_ints_disabled());

    const uint64_t tsc_freq = has_pvclock ? pvclock_get_tsc_freq() : x86_lookup_tsc_freq();
    if (tsc_freq != 0) {
        tsc_ticks_per_ms = tsc_freq / 1000;
        printf("TSC frequency: %" PRIu64 " ticks/ms\n", tsc_ticks_per_ms);
    } else {
        printf("Could not find TSC frequency: Calibrating TSC with %s\n",
               clock_name[calibration_clock]);

        uint32_t duration_ms[2] = {2, 4};
        uint64_t best_time[2] = {
            calibrate_tsc_count(static_cast<uint16_t>(duration_ms[0])),
            calibrate_tsc_count(static_cast<uint16_t>(duration_ms[1]))};

        while (best_time[0] >= best_time[1] && 2 * duration_ms[1] < MAX_TIMER_INTERVAL) {
            duration_ms[0] = duration_ms[1];
            duration_ms[1] *= 2;
            best_time[0] = best_time[1];
            best_time[1] = calibrate_tsc_count(static_cast<uint16_t>(duration_ms[1]));
        }

        ASSERT(best_time[0] < best_time[1]);

        tsc_ticks_per_ms = (best_time[1] - best_time[0]) / (duration_ms[1] - duration_ms[0]);

        printf("TSC calibrated: %" PRIu64 " ticks/ms\n", tsc_ticks_per_ms);
    }

    ASSERT(tsc_ticks_per_ms <= UINT32_MAX);
    fp_32_64_div_32_32(&ns_per_tsc, 1000 * 1000, static_cast<uint32_t>(tsc_ticks_per_ms));
    fp_32_64_div_32_32(&tsc_per_ns, static_cast<uint32_t>(tsc_ticks_per_ms), 1000 * 1000);
    // Add 1ns to conservatively deal with rounding
    ns_per_tsc_rounded_up = u32_mul_u64_fp32_64(1, ns_per_tsc) + 1;

    LTRACEF("ns_per_tsc: %08x.%08x%08x\n", ns_per_tsc.l0, ns_per_tsc.l32, ns_per_tsc.l64);
}
示例#4
0
文件: virtio-gpu.c 项目: 0xBADCA7/lk
void virtio_gpu_gfx_flush(uint starty, uint endy)
{
    event_signal(&the_gdev->flush_event, !arch_ints_disabled());
}
示例#5
0
static void calibrate_apic_timer(void) {
    ASSERT(arch_ints_disabled());

    const uint64_t apic_freq = x86_lookup_core_crystal_freq();
    if (apic_freq != 0) {
        ASSERT(apic_freq / 1000 <= UINT32_MAX);
        apic_ticks_per_ms = static_cast<uint32_t>(apic_freq / 1000);
        apic_divisor = 1;
        fp_32_64_div_32_32(&apic_ticks_per_ns, apic_ticks_per_ms, 1000 * 1000);
        printf("APIC frequency: %" PRIu32 " ticks/ms\n", apic_ticks_per_ms);
        return;
    }

    printf("Could not find APIC frequency: Calibrating APIC with %s\n",
           clock_name[calibration_clock]);

    apic_divisor = 1;
outer:
    while (apic_divisor != 0) {
        uint32_t best_time[2] = {UINT32_MAX, UINT32_MAX};
        const uint16_t duration_ms[2] = {2, 4};
        for (int trial = 0; trial < 2; ++trial) {
            for (int tries = 0; tries < 3; ++tries) {
                switch (calibration_clock) {
                case CLOCK_HPET:
                    hpet_calibration_cycle_preamble();
                    break;
                case CLOCK_PIT:
                    pit_calibration_cycle_preamble(duration_ms[trial]);
                    break;
                default:
                    PANIC_UNIMPLEMENTED;
                }

                // Setup APIC timer to count down with interrupt masked
                zx_status_t status = apic_timer_set_oneshot(
                    UINT32_MAX,
                    apic_divisor,
                    true);
                ASSERT(status == ZX_OK);

                switch (calibration_clock) {
                case CLOCK_HPET:
                    hpet_calibration_cycle(duration_ms[trial]);
                    break;
                case CLOCK_PIT:
                    pit_calibration_cycle(duration_ms[trial]);
                    break;
                default:
                    PANIC_UNIMPLEMENTED;
                }

                uint32_t apic_ticks = UINT32_MAX - apic_timer_current_count();
                if (apic_ticks < best_time[trial]) {
                    best_time[trial] = apic_ticks;
                }
                LTRACEF("Calibration trial %d found %u ticks/ms\n",
                        tries, apic_ticks);

                switch (calibration_clock) {
                case CLOCK_HPET:
                    hpet_calibration_cycle_cleanup();
                    break;
                case CLOCK_PIT:
                    pit_calibration_cycle_cleanup();
                    break;
                default:
                    PANIC_UNIMPLEMENTED;
                }
            }

            // If the APIC ran out of time every time, try again with a higher
            // divisor
            if (best_time[trial] == UINT32_MAX) {
                apic_divisor = static_cast<uint8_t>(apic_divisor * 2);
                goto outer;
            }
        }
        apic_ticks_per_ms = (best_time[1] - best_time[0]) / (duration_ms[1] - duration_ms[0]);
        fp_32_64_div_32_32(&apic_ticks_per_ns, apic_ticks_per_ms, 1000 * 1000);
        break;
    }
    ASSERT(apic_divisor != 0);

    printf("APIC timer calibrated: %" PRIu32 " ticks/ms, divisor %d\n",
           apic_ticks_per_ms, apic_divisor);
}