#include #include #include #include #include #include #include #include #include #include #include #include #include #include struct uacpi_runtime_context g_uacpi_rt_ctx = { 0 }; void uacpi_context_set_log_level(uacpi_log_level lvl) { if (lvl == 0) lvl = UACPI_DEFAULT_LOG_LEVEL; g_uacpi_rt_ctx.log_level = lvl; } void uacpi_logger_initialize(void) { static uacpi_bool version_printed = UACPI_FALSE; if (g_uacpi_rt_ctx.log_level == 0) uacpi_context_set_log_level(UACPI_DEFAULT_LOG_LEVEL); if (!version_printed) { version_printed = UACPI_TRUE; uacpi_info( "starting uACPI, version %d.%d.%d\n", UACPI_MAJOR, UACPI_MINOR, UACPI_PATCH ); } } void uacpi_context_set_proactive_table_checksum(uacpi_bool setting) { if (setting) g_uacpi_rt_ctx.flags |= UACPI_FLAG_PROACTIVE_TBL_CSUM; else g_uacpi_rt_ctx.flags &= ~UACPI_FLAG_PROACTIVE_TBL_CSUM; } const uacpi_char *uacpi_status_to_string(uacpi_status st) { switch (st) { case UACPI_STATUS_OK: return "no error"; case UACPI_STATUS_MAPPING_FAILED: return "failed to map memory"; case UACPI_STATUS_OUT_OF_MEMORY: return "out of memory"; case UACPI_STATUS_BAD_CHECKSUM: return "bad table checksum"; case UACPI_STATUS_INVALID_SIGNATURE: return "invalid table signature"; case UACPI_STATUS_INVALID_TABLE_LENGTH: return "invalid table length"; case UACPI_STATUS_NOT_FOUND: return "not found"; case UACPI_STATUS_INVALID_ARGUMENT: return "invalid argument"; case UACPI_STATUS_UNIMPLEMENTED: return "unimplemented"; case UACPI_STATUS_ALREADY_EXISTS: return "already exists"; case UACPI_STATUS_INTERNAL_ERROR: return "internal error"; case UACPI_STATUS_TYPE_MISMATCH: return "object type mismatch"; case UACPI_STATUS_INIT_LEVEL_MISMATCH: return "init level too low/high for this action"; case UACPI_STATUS_NAMESPACE_NODE_DANGLING: return "attempting to use a dangling namespace node"; case UACPI_STATUS_NO_HANDLER: return "no handler found"; case UACPI_STATUS_NO_RESOURCE_END_TAG: return "resource template without an end tag"; case UACPI_STATUS_COMPILED_OUT: return "this functionality has been compiled out of this build"; case UACPI_STATUS_HARDWARE_TIMEOUT: return "timed out waiting for hardware response"; case UACPI_STATUS_TIMEOUT: return "wait timed out"; case UACPI_STATUS_OVERRIDDEN: return "the requested action has been overridden"; case UACPI_STATUS_DENIED: return "the requested action has been denied"; case UACPI_STATUS_AML_UNDEFINED_REFERENCE: return "AML referenced an undefined object"; case UACPI_STATUS_AML_INVALID_NAMESTRING: return "invalid AML name string"; case UACPI_STATUS_AML_OBJECT_ALREADY_EXISTS: return "object already exists"; case UACPI_STATUS_AML_INVALID_OPCODE: return "invalid AML opcode"; case UACPI_STATUS_AML_INCOMPATIBLE_OBJECT_TYPE: return "incompatible AML object type"; case UACPI_STATUS_AML_BAD_ENCODING: return "bad AML instruction encoding"; case UACPI_STATUS_AML_OUT_OF_BOUNDS_INDEX: return "out of bounds AML index"; case UACPI_STATUS_AML_SYNC_LEVEL_TOO_HIGH: return "AML attempted to acquire a mutex with a lower sync level"; case UACPI_STATUS_AML_INVALID_RESOURCE: return "invalid resource template encoding or type"; case UACPI_STATUS_AML_LOOP_TIMEOUT: return "hanging AML while loop"; case UACPI_STATUS_AML_CALL_STACK_DEPTH_LIMIT: return "reached maximum AML call stack depth"; default: return ""; } } void uacpi_state_reset(void) { #ifndef UACPI_BAREBONES_MODE uacpi_deinitialize_namespace(); uacpi_deinitialize_interfaces(); uacpi_deinitialize_events(); uacpi_deinitialize_notify(); uacpi_deinitialize_opregion(); #endif uacpi_deinitialize_tables(); #ifndef UACPI_BAREBONES_MODE #ifndef UACPI_REDUCED_HARDWARE if (g_uacpi_rt_ctx.was_in_legacy_mode) uacpi_leave_acpi_mode(); #endif uacpi_deinitialize_registers(); #ifndef UACPI_REDUCED_HARDWARE if (g_uacpi_rt_ctx.global_lock_event) uacpi_kernel_free_event(g_uacpi_rt_ctx.global_lock_event); if (g_uacpi_rt_ctx.global_lock_spinlock) uacpi_kernel_free_spinlock(g_uacpi_rt_ctx.global_lock_spinlock); #endif #endif // !UACPI_BAREBONES_MODE uacpi_memzero(&g_uacpi_rt_ctx, sizeof(g_uacpi_rt_ctx)); #if defined(UACPI_KERNEL_INITIALIZATION) && !defined(UACPI_BAREBONES_MODE) uacpi_kernel_deinitialize(); #endif } #ifndef UACPI_BAREBONES_MODE void uacpi_context_set_loop_timeout(uacpi_u32 seconds) { if (seconds == 0) seconds = UACPI_DEFAULT_LOOP_TIMEOUT_SECONDS; g_uacpi_rt_ctx.loop_timeout_seconds = seconds; } void uacpi_context_set_max_call_stack_depth(uacpi_u32 depth) { if (depth == 0) depth = UACPI_DEFAULT_MAX_CALL_STACK_DEPTH; g_uacpi_rt_ctx.max_call_stack_depth = depth; } uacpi_u32 uacpi_context_get_loop_timeout(void) { return g_uacpi_rt_ctx.loop_timeout_seconds; } #ifndef UACPI_REDUCED_HARDWARE enum hw_mode { HW_MODE_ACPI = 0, HW_MODE_LEGACY = 1, }; static enum hw_mode read_mode(void) { uacpi_status ret; uacpi_u64 raw_value; struct acpi_fadt *fadt = &g_uacpi_rt_ctx.fadt; if (!fadt->smi_cmd) return HW_MODE_ACPI; ret = uacpi_read_register_field(UACPI_REGISTER_FIELD_SCI_EN, &raw_value); if (uacpi_unlikely_error(ret)) return HW_MODE_LEGACY; return raw_value ? HW_MODE_ACPI : HW_MODE_LEGACY; } static uacpi_status set_mode(enum hw_mode mode) { uacpi_status ret; uacpi_u64 raw_value, stalled_time = 0; struct acpi_fadt *fadt = &g_uacpi_rt_ctx.fadt; if (uacpi_unlikely(!fadt->smi_cmd)) { uacpi_error("SMI_CMD is not implemented by the firmware\n"); return UACPI_STATUS_NOT_FOUND; } if (uacpi_unlikely(!fadt->acpi_enable && !fadt->acpi_disable)) { uacpi_error("mode transition is not implemented by the hardware\n"); return UACPI_STATUS_NOT_FOUND; } switch (mode) { case HW_MODE_ACPI: raw_value = fadt->acpi_enable; break; case HW_MODE_LEGACY: raw_value = fadt->acpi_disable; break; default: return UACPI_STATUS_INVALID_ARGUMENT; } ret = uacpi_write_register(UACPI_REGISTER_SMI_CMD, raw_value); if (uacpi_unlikely_error(ret)) return ret; // Allow up to 5 seconds for the hardware to enter the desired mode while (stalled_time < (5 * 1000 * 1000)) { if (read_mode() == mode) return UACPI_STATUS_OK; uacpi_kernel_stall(100); stalled_time += 100; } uacpi_error("hardware time out while changing modes\n"); return UACPI_STATUS_HARDWARE_TIMEOUT; } static uacpi_status enter_mode(enum hw_mode mode, uacpi_bool *did_change) { uacpi_status ret; const uacpi_char *mode_str; UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); if (uacpi_is_hardware_reduced()) return UACPI_STATUS_OK; mode_str = mode == HW_MODE_LEGACY ? "legacy" : "acpi"; if (read_mode() == mode) { uacpi_trace("%s mode already enabled\n", mode_str); return UACPI_STATUS_OK; } ret = set_mode(mode); if (uacpi_unlikely_error(ret)) { uacpi_warn( "unable to enter %s mode: %s\n", mode_str, uacpi_status_to_string(ret) ); return ret; } uacpi_trace("entered %s mode\n", mode_str); if (did_change != UACPI_NULL) *did_change = UACPI_TRUE; return ret; } uacpi_status uacpi_enter_acpi_mode(void) { return enter_mode(HW_MODE_ACPI, UACPI_NULL); } uacpi_status uacpi_leave_acpi_mode(void) { return enter_mode(HW_MODE_LEGACY, UACPI_NULL); } static void enter_acpi_mode_initial(void) { enter_mode(HW_MODE_ACPI, &g_uacpi_rt_ctx.was_in_legacy_mode); } #else static void enter_acpi_mode_initial(void) { } #endif uacpi_init_level uacpi_get_current_init_level(void) { return g_uacpi_rt_ctx.init_level; } uacpi_status uacpi_initialize(uacpi_u64 flags) { uacpi_status ret; UACPI_ENSURE_INIT_LEVEL_IS(UACPI_INIT_LEVEL_EARLY); #ifdef UACPI_KERNEL_INITIALIZATION ret = uacpi_kernel_initialize(UACPI_INIT_LEVEL_EARLY); if (uacpi_unlikely_error(ret)) return ret; #endif g_uacpi_rt_ctx.init_level = UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED; g_uacpi_rt_ctx.last_sleep_typ_a = UACPI_SLEEP_TYP_INVALID; g_uacpi_rt_ctx.last_sleep_typ_b = UACPI_SLEEP_TYP_INVALID; g_uacpi_rt_ctx.s0_sleep_typ_a = UACPI_SLEEP_TYP_INVALID; g_uacpi_rt_ctx.s0_sleep_typ_b = UACPI_SLEEP_TYP_INVALID; g_uacpi_rt_ctx.flags = flags; uacpi_logger_initialize(); if (g_uacpi_rt_ctx.loop_timeout_seconds == 0) uacpi_context_set_loop_timeout(UACPI_DEFAULT_LOOP_TIMEOUT_SECONDS); if (g_uacpi_rt_ctx.max_call_stack_depth == 0) uacpi_context_set_max_call_stack_depth(UACPI_DEFAULT_MAX_CALL_STACK_DEPTH); ret = uacpi_initialize_tables(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; ret = uacpi_initialize_registers(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; ret = uacpi_initialize_events_early(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; ret = uacpi_initialize_opregion(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; ret = uacpi_initialize_interfaces(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; ret = uacpi_initialize_namespace(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; ret = uacpi_initialize_notify(); if (uacpi_unlikely_error(ret)) goto out_fatal_error; uacpi_install_default_address_space_handlers(); if (!uacpi_check_flag(UACPI_FLAG_NO_ACPI_MODE)) enter_acpi_mode_initial(); return UACPI_STATUS_OK; out_fatal_error: uacpi_state_reset(); return ret; } struct table_load_stats { uacpi_u32 load_counter; uacpi_u32 failure_counter; }; static void trace_table_load_failure( struct acpi_sdt_hdr *tbl, uacpi_log_level lvl, uacpi_status ret ) { uacpi_log_lvl( lvl, "failed to load "UACPI_PRI_TBL_HDR": %s\n", UACPI_FMT_TBL_HDR(tbl), uacpi_status_to_string(ret) ); } static uacpi_bool match_ssdt_or_psdt(struct uacpi_installed_table *tbl) { if (tbl->flags & UACPI_TABLE_LOADED) return UACPI_FALSE; return uacpi_signatures_match(tbl->hdr.signature, ACPI_SSDT_SIGNATURE) || uacpi_signatures_match(tbl->hdr.signature, ACPI_PSDT_SIGNATURE); } static uacpi_u64 elapsed_ms(uacpi_u64 begin_ns, uacpi_u64 end_ns) { return (end_ns - begin_ns) / (1000ull * 1000ull); } static uacpi_bool warn_on_bad_timesource(uacpi_u64 begin_ts, uacpi_u64 end_ts) { const uacpi_char *reason; if (uacpi_unlikely(begin_ts == 0 && end_ts == 0)) { reason = "uacpi_kernel_get_nanoseconds_since_boot() appears to be a stub"; goto out_bad_timesource; } if (uacpi_unlikely(begin_ts == end_ts)) { reason = "poor time source precision detected"; goto out_bad_timesource; } if (uacpi_unlikely(end_ts < begin_ts)) { reason = "time source backwards drift detected"; goto out_bad_timesource; } return UACPI_FALSE; out_bad_timesource: uacpi_warn("%s, this may cause problems\n", reason); return UACPI_TRUE; } uacpi_status uacpi_namespace_load(void) { struct uacpi_table tbl; uacpi_status ret; uacpi_u64 begin_ts, end_ts; struct table_load_stats st = { 0 }; uacpi_size cur_index; UACPI_ENSURE_INIT_LEVEL_IS(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); #ifdef UACPI_KERNEL_INITIALIZATION ret = uacpi_kernel_initialize(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); if (uacpi_unlikely_error(ret)) goto out_fatal_error; #endif begin_ts = uacpi_kernel_get_nanoseconds_since_boot(); ret = uacpi_table_find_by_signature(ACPI_DSDT_SIGNATURE, &tbl); if (uacpi_unlikely_error(ret)) { uacpi_error("unable to find DSDT: %s\n", uacpi_status_to_string(ret)); goto out_fatal_error; } ret = uacpi_table_load_with_cause(tbl.index, UACPI_TABLE_LOAD_CAUSE_INIT); if (uacpi_unlikely_error(ret)) { trace_table_load_failure(tbl.hdr, UACPI_LOG_ERROR, ret); st.failure_counter++; } st.load_counter++; uacpi_table_unref(&tbl); for (cur_index = 0;; cur_index = tbl.index + 1) { ret = uacpi_table_match(cur_index, match_ssdt_or_psdt, &tbl); if (ret != UACPI_STATUS_OK) { if (uacpi_unlikely(ret != UACPI_STATUS_NOT_FOUND)) goto out_fatal_error; break; } ret = uacpi_table_load_with_cause(tbl.index, UACPI_TABLE_LOAD_CAUSE_INIT); if (uacpi_unlikely_error(ret)) { trace_table_load_failure(tbl.hdr, UACPI_LOG_WARN, ret); st.failure_counter++; } st.load_counter++; uacpi_table_unref(&tbl); } end_ts = uacpi_kernel_get_nanoseconds_since_boot(); g_uacpi_rt_ctx.bad_timesource = warn_on_bad_timesource(begin_ts, end_ts); if (uacpi_unlikely(st.failure_counter != 0 || g_uacpi_rt_ctx.bad_timesource)) { uacpi_info( "loaded %u AML blob%s (%u error%s)\n", st.load_counter, st.load_counter > 1 ? "s" : "", st.failure_counter, st.failure_counter == 1 ? "" : "s" ); } else { uacpi_u64 ops = g_uacpi_rt_ctx.opcodes_executed; uacpi_u64 ops_per_sec = ops * UACPI_NANOSECONDS_PER_SEC; ops_per_sec /= end_ts - begin_ts; uacpi_info( "successfully loaded %u AML blob%s, %"UACPI_PRIu64" ops in " "%"UACPI_PRIu64"ms (avg %"UACPI_PRIu64"/s)\n", st.load_counter, st.load_counter > 1 ? "s" : "", UACPI_FMT64(ops), UACPI_FMT64(elapsed_ms(begin_ts, end_ts)), UACPI_FMT64(ops_per_sec) ); } ret = uacpi_initialize_events(); if (uacpi_unlikely_error(ret)) { uacpi_error("event initialization failed: %s\n", uacpi_status_to_string(ret)); goto out_fatal_error; } g_uacpi_rt_ctx.init_level = UACPI_INIT_LEVEL_NAMESPACE_LOADED; return UACPI_STATUS_OK; out_fatal_error: uacpi_state_reset(); return ret; } struct ns_init_context { uacpi_size ini_executed; uacpi_size ini_errors; uacpi_size sta_executed; uacpi_size sta_errors; uacpi_size devices; uacpi_size thermal_zones; }; static void ini_eval(struct ns_init_context *ctx, uacpi_namespace_node *node) { uacpi_status ret; ret = uacpi_eval(node, "_INI", UACPI_NULL, UACPI_NULL); if (ret == UACPI_STATUS_NOT_FOUND) return; ctx->ini_executed++; if (uacpi_unlikely_error(ret)) ctx->ini_errors++; } static uacpi_status sta_eval( struct ns_init_context *ctx, uacpi_namespace_node *node, uacpi_u32 *value ) { uacpi_status ret; ret = uacpi_eval_sta(node, value); if (*value == 0xFFFFFFFF) return ret; ctx->sta_executed++; if (uacpi_unlikely_error(ret)) ctx->sta_errors++; return ret; } static uacpi_iteration_decision do_sta_ini( void *opaque, uacpi_namespace_node *node, uacpi_u32 depth ) { struct ns_init_context *ctx = opaque; uacpi_status ret; uacpi_object_type type = UACPI_OBJECT_UNINITIALIZED; uacpi_u32 sta_ret; UACPI_UNUSED(depth); // We don't care about aliases if (uacpi_namespace_node_is_alias(node)) return UACPI_ITERATION_DECISION_NEXT_PEER; ret = uacpi_namespace_node_type(node, &type); switch (type) { case UACPI_OBJECT_DEVICE: case UACPI_OBJECT_PROCESSOR: ctx->devices++; break; case UACPI_OBJECT_THERMAL_ZONE: ctx->thermal_zones++; break; default: if (node != uacpi_namespace_get_predefined(UACPI_PREDEFINED_NAMESPACE_TZ)) return UACPI_ITERATION_DECISION_CONTINUE; } ret = sta_eval(ctx, node, &sta_ret); if (uacpi_unlikely_error(ret)) return UACPI_ITERATION_DECISION_CONTINUE; if (!(sta_ret & ACPI_STA_RESULT_DEVICE_PRESENT)) { if (!(sta_ret & ACPI_STA_RESULT_DEVICE_FUNCTIONING)) return UACPI_ITERATION_DECISION_NEXT_PEER; /* * ACPI 6.5 specification: * _STA may return bit 0 clear (not present) with bit [3] set (device * is functional). This case is used to indicate a valid device for * which no device driver should be loaded (for example, a bridge * device.) Children of this device may be present and valid. OSPM * should continue enumeration below a device whose _STA returns this * bit combination. */ return UACPI_ITERATION_DECISION_CONTINUE; } ini_eval(ctx, node); return UACPI_ITERATION_DECISION_CONTINUE; } uacpi_status uacpi_namespace_initialize(void) { struct ns_init_context ctx = { 0 }; uacpi_namespace_node *root; uacpi_u64 begin_ts, end_ts; uacpi_address_space_handlers *handlers; uacpi_address_space_handler *handler; uacpi_status ret = UACPI_STATUS_OK; UACPI_ENSURE_INIT_LEVEL_IS(UACPI_INIT_LEVEL_NAMESPACE_LOADED); #ifdef UACPI_KERNEL_INITIALIZATION ret = uacpi_kernel_initialize(UACPI_INIT_LEVEL_NAMESPACE_LOADED); if (uacpi_unlikely_error(ret)) goto out; #endif /* * Initialization order here is identical to ACPICA because ACPI * specification doesn't really have any detailed steps that explain * how to do it. */ root = uacpi_namespace_root(); begin_ts = uacpi_kernel_get_nanoseconds_since_boot(); // Step 1 - Execute \_INI ini_eval(&ctx, root); // Step 2 - Execute \_SB._INI ini_eval( &ctx, uacpi_namespace_get_predefined(UACPI_PREDEFINED_NAMESPACE_SB) ); /* * Step 3 - Run _REG methods for all globally installed * address space handlers. */ handlers = uacpi_node_get_address_space_handlers(root); if (handlers) { handler = handlers->head; while (handler) { if (uacpi_address_space_handler_is_default(handler)) uacpi_reg_all_opregions(root, handler->space); handler = handler->next; } } // Step 4 - Run all other _STA and _INI methods uacpi_namespace_for_each_child( root, do_sta_ini, UACPI_NULL, UACPI_OBJECT_ANY_BIT, UACPI_MAX_DEPTH_ANY, &ctx ); end_ts = uacpi_kernel_get_nanoseconds_since_boot(); if (uacpi_likely(!g_uacpi_rt_ctx.bad_timesource)) { uacpi_info( "namespace initialization done in %"UACPI_PRIu64"ms: " "%zu devices, %zu thermal zones\n", UACPI_FMT64(elapsed_ms(begin_ts, end_ts)), ctx.devices, ctx.thermal_zones ); } else { uacpi_info( "namespace initialization done: %zu devices, %zu thermal zones\n", ctx.devices, ctx.thermal_zones ); } uacpi_trace( "_STA calls: %zu (%zu errors), _INI calls: %zu (%zu errors)\n", ctx.sta_executed, ctx.sta_errors, ctx.ini_executed, ctx.ini_errors ); g_uacpi_rt_ctx.init_level = UACPI_INIT_LEVEL_NAMESPACE_INITIALIZED; #ifdef UACPI_KERNEL_INITIALIZATION ret = uacpi_kernel_initialize(UACPI_INIT_LEVEL_NAMESPACE_INITIALIZED); out: if (uacpi_unlikely_error(ret)) uacpi_state_reset(); #endif return ret; } uacpi_status uacpi_eval( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_object **out_obj ) { struct uacpi_namespace_node *node; uacpi_control_method *method; uacpi_object *obj; uacpi_status ret = UACPI_STATUS_INVALID_ARGUMENT; if (uacpi_unlikely(parent == UACPI_NULL && path == UACPI_NULL)) return ret; ret = uacpi_namespace_read_lock(); if (uacpi_unlikely_error(ret)) return ret; if (path != UACPI_NULL) { ret = uacpi_namespace_node_resolve( parent, path, UACPI_SHOULD_LOCK_NO, UACPI_MAY_SEARCH_ABOVE_PARENT_NO, UACPI_PERMANENT_ONLY_YES, &node ); if (uacpi_unlikely_error(ret)) goto out_read_unlock; } else { node = parent; } obj = uacpi_namespace_node_get_object(node); if (uacpi_unlikely(obj == UACPI_NULL)) { ret = UACPI_STATUS_INVALID_ARGUMENT; goto out_read_unlock; } if (obj->type != UACPI_OBJECT_METHOD) { uacpi_object *new_obj; if (uacpi_unlikely(out_obj == UACPI_NULL)) goto out_read_unlock; new_obj = uacpi_create_object(UACPI_OBJECT_UNINITIALIZED); if (uacpi_unlikely(new_obj == UACPI_NULL)) { ret = UACPI_STATUS_OUT_OF_MEMORY; goto out_read_unlock; } ret = uacpi_object_assign( new_obj, obj, UACPI_ASSIGN_BEHAVIOR_DEEP_COPY ); if (uacpi_unlikely_error(ret)) { uacpi_object_unref(new_obj); goto out_read_unlock; } *out_obj = new_obj; out_read_unlock: uacpi_namespace_read_unlock(); return ret; } method = obj->method; uacpi_shareable_ref(method); uacpi_namespace_read_unlock(); // Upgrade to a write-lock since we're about to run a method ret = uacpi_namespace_write_lock(); if (uacpi_unlikely_error(ret)) goto out_no_write_lock; ret = uacpi_execute_control_method(node, method, args, out_obj); uacpi_namespace_write_unlock(); out_no_write_lock: uacpi_method_unref(method); return ret; } uacpi_status uacpi_eval_simple( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret ) { return uacpi_eval(parent, path, UACPI_NULL, ret); } uacpi_status uacpi_execute( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args ) { return uacpi_eval(parent, path, args, UACPI_NULL); } uacpi_status uacpi_execute_simple( uacpi_namespace_node *parent, const uacpi_char *path ) { return uacpi_eval(parent, path, UACPI_NULL, UACPI_NULL); } #define TRACE_BAD_RET(path_fmt, type, ...) \ uacpi_warn( \ "unexpected '%s' object returned by method "path_fmt \ ", expected type mask: %08X\n", uacpi_object_type_to_string(type), \ __VA_ARGS__ \ ) #define TRACE_NO_RET(path_fmt, ...) \ uacpi_warn( \ "no value returned from method "path_fmt", expected type mask: " \ "%08X\n", __VA_ARGS__ \ ) static void trace_invalid_return_type( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object_type_bits expected_mask, uacpi_object_type actual_type ) { const uacpi_char *abs_path; uacpi_bool dynamic_abs_path = UACPI_FALSE; if (parent == UACPI_NULL || (path != UACPI_NULL && path[0] == '\\')) { abs_path = path; } else { abs_path = uacpi_namespace_node_generate_absolute_path(parent); dynamic_abs_path = UACPI_TRUE; } if (dynamic_abs_path && path != UACPI_NULL) { if (actual_type == UACPI_OBJECT_UNINITIALIZED) TRACE_NO_RET("%s.%s", abs_path, path, expected_mask); else TRACE_BAD_RET("%s.%s", actual_type, abs_path, path, expected_mask); } else { if (actual_type == UACPI_OBJECT_UNINITIALIZED) { TRACE_NO_RET("%s", abs_path, expected_mask); } else { TRACE_BAD_RET("%s", actual_type, abs_path, expected_mask); } } if (dynamic_abs_path) uacpi_free_dynamic_string(abs_path); } uacpi_status uacpi_eval_typed( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_object_type_bits ret_mask, uacpi_object **out_obj ) { uacpi_status ret; uacpi_object *obj; uacpi_object_type returned_type = UACPI_OBJECT_UNINITIALIZED; if (uacpi_unlikely(out_obj == UACPI_NULL)) return UACPI_STATUS_INVALID_ARGUMENT; ret = uacpi_eval(parent, path, args, &obj); if (uacpi_unlikely_error(ret)) return ret; if (obj != UACPI_NULL) returned_type = obj->type; if (ret_mask && (ret_mask & (1 << returned_type)) == 0) { trace_invalid_return_type(parent, path, ret_mask, returned_type); uacpi_object_unref(obj); return UACPI_STATUS_TYPE_MISMATCH; } *out_obj = obj; return UACPI_STATUS_OK; } uacpi_status uacpi_eval_simple_typed( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object_type_bits ret_mask, uacpi_object **ret ) { return uacpi_eval_typed(parent, path, UACPI_NULL, ret_mask, ret); } uacpi_status uacpi_eval_integer( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_u64 *out_value ) { uacpi_object *int_obj; uacpi_status ret; ret = uacpi_eval_typed( parent, path, args, UACPI_OBJECT_INTEGER_BIT, &int_obj ); if (uacpi_unlikely_error(ret)) return ret; *out_value = int_obj->integer; uacpi_object_unref(int_obj); return UACPI_STATUS_OK; } uacpi_status uacpi_eval_simple_integer( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_u64 *out_value ) { return uacpi_eval_integer(parent, path, UACPI_NULL, out_value); } uacpi_status uacpi_eval_buffer_or_string( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, args, UACPI_OBJECT_BUFFER_BIT | UACPI_OBJECT_STRING_BIT, ret ); } uacpi_status uacpi_eval_simple_buffer_or_string( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, UACPI_NULL, UACPI_OBJECT_BUFFER_BIT | UACPI_OBJECT_STRING_BIT, ret ); } uacpi_status uacpi_eval_string( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, args, UACPI_OBJECT_STRING_BIT, ret ); } uacpi_status uacpi_eval_simple_string( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, UACPI_NULL, UACPI_OBJECT_STRING_BIT, ret ); } uacpi_status uacpi_eval_buffer( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, args, UACPI_OBJECT_BUFFER_BIT, ret ); } uacpi_status uacpi_eval_simple_buffer( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, UACPI_NULL, UACPI_OBJECT_BUFFER_BIT, ret ); } uacpi_status uacpi_eval_package( uacpi_namespace_node *parent, const uacpi_char *path, const uacpi_object_array *args, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, args, UACPI_OBJECT_PACKAGE_BIT, ret ); } uacpi_status uacpi_eval_simple_package( uacpi_namespace_node *parent, const uacpi_char *path, uacpi_object **ret ) { return uacpi_eval_typed( parent, path, UACPI_NULL, UACPI_OBJECT_PACKAGE_BIT, ret ); } uacpi_status uacpi_get_aml_bitness(uacpi_u8 *out_bitness) { UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED); *out_bitness = g_uacpi_rt_ctx.is_rev1 ? 32 : 64; return UACPI_STATUS_OK; } #endif // !UACPI_BAREBONES_MODE