示例#1
0
// Finish processing of the transition to State::DEAD. Some things need to be done
// outside of holding |get_lock()|. Beware this is called from several places
// including on_zero_handles().
void ProcessDispatcher::FinishDeadTransition() {
    DEBUG_ASSERT(!completely_dead_);
    completely_dead_ = true;

    // clean up the handle table
    LTRACEF_LEVEL(2, "cleaning up handle table on proc %p\n", this);

    fbl::DoublyLinkedList<Handle*> to_clean;
    {
        Guard<fbl::Mutex> guard{&handle_table_lock_};
        for (auto& handle : handles_) {
            handle.set_process_id(ZX_KOID_INVALID);
        }
        to_clean.swap(handles_);
    }

    // zx-1544: Here is where if we're the last holder of a handle of one of
    // our exception ports then ResetExceptionPort will get called (by
    // ExceptionPort::OnPortZeroHandles) and will need to grab |get_lock()|.
    // This needs to be done outside of |get_lock()|.
    while (!to_clean.is_empty()) {
        // Delete handle via HandleOwner dtor.
        HandleOwner ho(to_clean.pop_front());
    }

    LTRACEF_LEVEL(2, "done cleaning up handle table on proc %p\n", this);

    // tear down the address space
    aspace_->Destroy();

    // signal waiter
    LTRACEF_LEVEL(2, "signaling waiters\n");
    UpdateState(0u, ZX_TASK_TERMINATED);

    // The PROC_CREATE record currently emits a uint32_t koid.
    uint32_t koid = static_cast<uint32_t>(get_koid());
    ktrace(TAG_PROC_EXIT, koid, 0, 0, 0);

    // Call job_->RemoveChildProcess(this) outside of |get_lock()|. Otherwise
    // we risk a deadlock as we have |get_lock()| and RemoveChildProcess grabs
    // the job's |lock_|, whereas JobDispatcher::EnumerateChildren obtains the
    // locks in the opposite order. We want to keep lock acquisition order
    // consistent, and JobDispatcher::EnumerateChildren's order makes
    // sense. We don't need |get_lock()| when calling RemoveChildProcess
    // here. ZX-880
    // RemoveChildProcess is called soon after releasing |get_lock()| so that
    // the semantics of signaling ZX_JOB_NO_PROCESSES match that of
    // ZX_TASK_TERMINATED.
    job_->RemoveChildProcess(this);
}
示例#2
0
static void test_lk_time_to_cntpct(uint32_t cntfrq, lk_time_t lk_time)
{
	uint64_t cntpct = lk_time_to_cntpct(lk_time);
	uint64_t expected_cntpct = ((uint64_t)cntfrq * lk_time + 500) / 1000;

	test_time_conversion_check_result(cntpct, expected_cntpct, 1, false);
	LTRACEF_LEVEL(2, "lk_time_to_cntpct(%u): got %llu, expect %llu\n", lk_time, cntpct, expected_cntpct);
}
示例#3
0
static uint64_t read_cntpct(void)
{
	uint64_t cntpct;

	cntpct = READ_TIMER_REG64(TIMER_REG_CT);
	LTRACEF_LEVEL(3, "cntpct: 0x%016llx, %llu\n", cntpct, cntpct);
	return cntpct;
}
示例#4
0
static void test_cntpct_to_lk_bigtime(uint32_t cntfrq, uint64_t expected_s)
{
	lk_bigtime_t expected_lk_bigtime = expected_s * 1000 * 1000;
	uint64_t cntpct = (uint64_t)cntfrq * expected_s;
	lk_bigtime_t lk_bigtime = cntpct_to_lk_bigtime(cntpct);

	test_time_conversion_check_result(lk_bigtime, expected_lk_bigtime, (1000 * 1000 + cntfrq - 1) / cntfrq, false);
	LTRACEF_LEVEL(2, "cntpct_to_lk_bigtime(%llu): got %llu, expect %llu\n", cntpct, lk_bigtime, expected_lk_bigtime);
}
示例#5
0
static void test_cntpct_to_lk_time(uint32_t cntfrq, lk_time_t expected_lk_time, uint32_t wrap_count)
{
	lk_time_t lk_time;
	uint64_t cntpct;

	cntpct = (uint64_t)cntfrq * expected_lk_time / 1000;
	if ((uint64_t)cntfrq * wrap_count > UINT_MAX)
		cntpct += (((uint64_t)cntfrq << 32) / 1000) * wrap_count;
	else
		cntpct += (((uint64_t)(cntfrq * wrap_count) << 32) / 1000);
	lk_time = cntpct_to_lk_time(cntpct);

	test_time_conversion_check_result(lk_time, expected_lk_time, (1000 + cntfrq - 1) / cntfrq, true);
	LTRACEF_LEVEL(2, "cntpct_to_lk_time(%llu): got %u, expect %u\n", cntpct, lk_time, expected_lk_time);
}
示例#6
0
static void write_cntp_tval(int32_t cntp_tval)
{
	LTRACEF_LEVEL(3, "cntp_tval: 0x%08x, %d\n", cntp_tval, cntp_tval);
	WRITE_TIMER_REG32(TIMER_REG_TVAL, cntp_tval);
}
示例#7
0
static void write_cntp_cval(uint64_t cntp_cval)
{
	LTRACEF_LEVEL(3, "cntp_cval: 0x%016llx, %llu\n", cntp_cval, cntp_cval);
	WRITE_TIMER_REG64(TIMER_REG_CVAL, cntp_cval);
}
示例#8
0
static void write_cntp_ctl(uint32_t cntp_ctl)
{
	LTRACEF_LEVEL(3, "cntp_ctl: 0x%x %x\n", cntp_ctl, read_cntp_ctl());
	WRITE_TIMER_REG32(TIMER_REG_CTL, cntp_ctl);
}
示例#9
0
zx_status_t InputDevice::Init() {
    LTRACEF("Device %p\n", this);

    fbl::AutoLock lock(&lock_);

    // Reset the device and read configuration
    DeviceReset();

    SelectConfig(VIRTIO_INPUT_CFG_ID_NAME, 0);
    LTRACEF_LEVEL(2, "name %s\n", config_.u.string);

    SelectConfig(VIRTIO_INPUT_CFG_ID_SERIAL, 0);
    LTRACEF_LEVEL(2, "serial %s\n", config_.u.string);

    SelectConfig(VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
    if (config_.size >= sizeof(virtio_input_devids_t)) {
        LTRACEF_LEVEL(2, "bustype %d\n", config_.u.ids.bustype);
        LTRACEF_LEVEL(2, "vendor %d\n", config_.u.ids.vendor);
        LTRACEF_LEVEL(2, "product %d\n", config_.u.ids.product);
        LTRACEF_LEVEL(2, "version %d\n", config_.u.ids.version);
    }

    SelectConfig(VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_EV_KEY);
    uint8_t cfg_key_size = config_.size;
    SelectConfig(VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_EV_REL);
    uint8_t cfg_rel_size = config_.size;
    SelectConfig(VIRTIO_INPUT_CFG_EV_BITS, VIRTIO_INPUT_EV_ABS);
    uint8_t cfg_abs_size = config_.size;

    // We only support one of pointer events or key events. In the advent that
    // the device is trying to present both to us we shall preference the
    // keyboard events as these are more useful to us.
    if (cfg_key_size > 0) {
        // Keyboard
        dev_class_ = HID_DEVICE_CLASS_KBD;
    } else if (cfg_rel_size > 0 || cfg_abs_size > 0) {
        // Pointer
        dev_class_ = HID_DEVICE_CLASS_POINTER;
    } else {
        return ZX_ERR_NOT_SUPPORTED;
    }

    DriverStatusAck();

    // Plan to clean up unless everything succeeds.
    auto cleanup = fbl::MakeAutoCall([this]() { Release(); });

    // Allocate the main vring
    zx_status_t status = vring_.Init(0, kEventCount);
    if (status != ZX_OK) {
        zxlogf(ERROR, "Failed to allocate vring: %s\n", zx_status_get_string(status));
        return status;
    }

    // Allocate event buffers for the ring.
    // TODO: Avoid multiple allocations, allocate enough for all buffers once.
    for (uint16_t id = 0; id < kEventCount; ++id) {
        static_assert(sizeof(virtio_input_event_t) <= PAGE_SIZE, "");
        status = io_buffer_init(&buffers_[id], bti_.get(), sizeof(virtio_input_event_t),
                                IO_BUFFER_RO | IO_BUFFER_CONTIG);
        if (status != ZX_OK) {
            zxlogf(ERROR, "Failed to allocate I/O buffers: %s\n", zx_status_get_string(status));
            return status;
        }
    }

    // Expose event buffers to the host
    vring_desc* desc = nullptr;
    uint16_t id;
    for (uint16_t i = 0; i < kEventCount; ++i) {
        desc = vring_.AllocDescChain(1, &id);
        if (desc == nullptr) {
            zxlogf(ERROR, "Failed to allocate descriptor chain\n");
            return ZX_ERR_NO_RESOURCES;
        }
        ZX_ASSERT(id < kEventCount);
        desc->addr = io_buffer_phys(&buffers_[id]);
        desc->len = sizeof(virtio_input_event_t);
        desc->flags |= VRING_DESC_F_WRITE;
        LTRACE_DO(virtio_dump_desc(desc));
        vring_.SubmitChain(id);
    }

    // Prepare the HID report buffer
    memset(&report_, 0, sizeof(report_));

    StartIrqThread();
    DriverStatusOk();

    device_ops_.release = virtio_input_release;

    hidbus_ops_.query = virtio_input_query;
    hidbus_ops_.start = virtio_input_start;
    hidbus_ops_.stop = virtio_input_stop;
    hidbus_ops_.get_descriptor = virtio_input_get_descriptor;
    hidbus_ops_.get_report = virtio_input_get_report;
    hidbus_ops_.set_report = virtio_input_set_report;
    hidbus_ops_.get_idle = virtio_input_get_idle;
    hidbus_ops_.set_idle = virtio_input_set_idle;
    hidbus_ops_.get_protocol = virtio_input_get_protocol;
    hidbus_ops_.set_protocol = virtio_input_set_protocol;

    hidbus_ifc_.ops = nullptr;

    device_add_args_t args = {};
    args.version = DEVICE_ADD_ARGS_VERSION;
    args.name = "virtio-input";
    args.ctx = this;
    args.ops = &device_ops_;
    args.proto_id = ZX_PROTOCOL_HIDBUS;
    args.proto_ops = &hidbus_ops_;

    status = device_add(bus_device_, &args, &device_);
    if (status != ZX_OK) {
        zxlogf(ERROR, "Failed to add device: %s\n", zx_status_get_string(status));
        device_ = nullptr;
        return status;
    }

    vring_.Kick();
    cleanup.cancel();
    return ZX_OK;
}