#pragma once #include #include #include #include #include #include #include #include #include #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else #define NORETURN #endif NORETURN static inline void error(const char *format, ...) { va_list args; fprintf(stderr, "unexpected error: "); va_start(args, format); vfprintf(stderr, format, args); va_end(args); fputc('\n', stderr); uacpi_state_reset(); exit(1); } static inline void *do_malloc(size_t size) { void *ptr = malloc(size); if (!ptr) error("failed to allocate %zu bytes of memory", size); return ptr; } static inline void *do_calloc(size_t nmemb, size_t size) { void *ptr = calloc(nmemb, size); if (!ptr) error("failed to allocate %zu bytes of memory", nmemb * size); return ptr; } static inline void *do_realloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (!ptr) error("failed to allocate %zu bytes of memory", size); return ptr; } typedef struct { void *data; size_t size; } blob_t; typedef struct { blob_t *blobs; size_t capacity; size_t count; } vector_t; static inline void vector_init(vector_t *vector, size_t items) { vector->blobs = do_calloc(items, sizeof(*vector->blobs)); vector->capacity = items; vector->count = items; } static inline void vector_add(vector_t *vector, void *data, size_t size) { if (vector->count >= vector->capacity) { vector->capacity = vector->capacity ? vector->capacity * 2 : 8; vector->blobs = do_realloc( vector->blobs, vector->capacity * sizeof(*vector->blobs) ); } vector->blobs[vector->count].data = data; vector->blobs[vector->count].size = size; vector->count += 1; } static inline void vector_cleanup(vector_t *vector) { free(vector->blobs); vector->capacity = 0; vector->count = 0; } static inline void *get_container(void *value, size_t offset) { return value ? (void*)((char*)value - offset) : NULL; } #define CONTAINER(type, field, value) \ ((type*)get_container((value), offsetof(type, field))) typedef struct hash_node { struct hash_node *prev; struct hash_node *next; uint64_t key; } hash_node_t; typedef struct { hash_node_t **entries; size_t capacity; size_t count; } hash_table_t; static inline uint64_t make_hash(uint64_t x) { x *= 0xe9770214b82cf957; x ^= x >> 47; x *= 0x2bdd9d20d060fc9b; x ^= x >> 44; x *= 0x65c487023b406173; return x; } static inline hash_node_t *hash_table_find(hash_table_t *table, uint64_t key) { hash_node_t *current; if (!table->capacity) return NULL; current = table->entries[make_hash(key) % table->capacity]; while (current != NULL && current->key != key) current = current->next; return current; } #define HASH_TABLE_FIND(table, key, type, field) \ CONTAINER(type, field, hash_table_find((table), (key))) static inline hash_node_t *hash_table_get_or_add( hash_table_t *table, uint64_t key, size_t size, size_t offset ) { uint64_t hash = make_hash(key); void *value; hash_node_t *node; size_t bucket; if (table->capacity) { hash_node_t *current = table->entries[hash % table->capacity]; while (current != NULL) { if (current->key == key) return current; current = current->next; } } if (table->count >= table->capacity - (table->capacity / 4)) { size_t new_cap = table->capacity ? table->capacity * 2 : 8; hash_node_t **new_entries = do_calloc(new_cap, sizeof(*table->entries)); size_t i; for (i = 0; i < table->capacity; i++) { hash_node_t *current = table->entries[i]; while (current != NULL) { hash_node_t *next = current->next; size_t bucket = make_hash(current->key) % new_cap; current->prev = NULL; current->next = new_entries[bucket]; if (current->next) current->next->prev = current; new_entries[bucket] = current; current = next; } } free(table->entries); table->entries = new_entries; table->capacity = new_cap; } value = do_calloc(1, size); node = (void*)((char*)value + offset); node->key = key; bucket = hash % table->capacity; node->prev = NULL; node->next = table->entries[bucket]; if (node->next) node->next->prev = node; table->entries[bucket] = node; table->count += 1; return node; } #define HASH_TABLE_GET_OR_ADD(table, key, type, field) \ CONTAINER( \ type, field, \ hash_table_get_or_add( \ (table), (key), sizeof(type), offsetof(type, field) \ ) \ ) static inline void hash_table_remove( hash_table_t *table, hash_node_t *node, size_t offset ) { if (node->prev) node->prev->next = node->next; else table->entries[make_hash(node->key) % table->capacity] = node->next; if (node->next) node->next->prev = node->prev; table->count -= 1; free((void*)((char*)node - offset)); } #define HASH_TABLE_REMOVE(table, value, type, field) \ hash_table_remove((table), &(value)->field, offsetof(type, field)) static inline bool hash_table_empty(hash_table_t *table) { return table->count == 0; } static inline void hash_table_cleanup(hash_table_t *table) { free(table->entries); table->capacity = 0; table->count = 0; } extern bool g_expect_virtual_addresses; extern uacpi_phys_addr g_rsdp; UACPI_PACKED(struct full_xsdt { struct acpi_sdt_hdr hdr; struct acpi_fadt *fadt; struct acpi_sdt_hdr *ssdts[]; }) void set_oem(char (*oemid)[6]); void set_oem_table_id(char (*oemid_table_id)[8]); struct full_xsdt *make_xsdt( struct acpi_rsdp *rsdp, const char *dsdt_path, const vector_t *ssdt_paths ); struct full_xsdt *make_xsdt_blob( struct acpi_rsdp *rsdp, const void *dsdt, size_t dsdt_size ); void delete_xsdt(struct full_xsdt *xsdt, size_t num_tables); blob_t read_entire_file(const char *path, size_t min_size); static inline void ensure_ok_status(uacpi_status st) { if (st == UACPI_STATUS_OK) return; error("uACPI error: %s", uacpi_status_to_string(st)); } static inline const char *uacpi_log_level_to_string(uacpi_log_level lvl) { switch (lvl) { case UACPI_LOG_DEBUG: return "DEBUG"; case UACPI_LOG_TRACE: return "TRACE"; case UACPI_LOG_INFO: return "INFO"; case UACPI_LOG_WARN: return "WARN"; case UACPI_LOG_ERROR: return "ERROR"; default: abort(); return NULL; } }