#include #include #include #include #include #define PREFIX "ACPI: " int sbf_port __initdata = -1; static bool acpi_os_initialized; u32 __attribute__((externally_visible)) drvEntry(int action, char *cmdline) { int result; if(action != 1) return 0; if( !dbg_open("/tmp0/1/acpi.log") ) { printk("Can't open /tmp0/1/acpi.log\nExit\n"); return 0; } dmi_scan_machine(); acpi_boot_table_init(); early_acpi_boot_init(); acpi_noirq_set(); acpi_early_init(); // if (acpi_disabled) { // printk(KERN_INFO PREFIX "Interpreter disabled.\n"); // return -ENODEV; // } // init_acpi_device_notify(); // result = acpi_bus_init(); // if (result) { // disable_acpi(); // return result; // } // pci_mmcfg_late_init(); // acpi_scan_init(); // acpi_ec_init(); // acpi_debugfs_init(); // acpi_sleep_proc_init(); // acpi_wakeup_device_init(); dbgprintf("module loaded\n"); return 0; }; #define PREFIX "ACPI: " u32 IMPORT AcpiGetRootPtr(void)__asm__("AcpiGetRootPtr"); acpi_physical_address __init acpi_os_get_root_pointer(void) { return AcpiGetRootPtr(); } void* acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { return (void *)MapIoMem((addr_t)phys, size, PG_SW); } void acpi_os_unmap_memory(void *virt, acpi_size size) { u32 ptr = (u32)virt; ptr &= 0xFFFFF000; return FreeKernelSpace((void*)ptr); } void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { acpi_os_unmap_memory(virt, size); } int acpi_os_map_generic_address(struct acpi_generic_address *gas) { addr_t addr; void *virt; if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; addr = (addr_t)gas->address; if (!addr || !gas->bit_width) return -EINVAL; virt = (void *)MapIoMem(addr, gas->bit_width / 8, PG_SW); if (!virt) return -EIO; return 0; } void acpi_os_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); acpi_os_vprintf(fmt, args); va_end(args); } void acpi_os_vprintf(const char *fmt, va_list args) { static char buffer[512]; vsprintf(buffer, fmt, args); #ifdef ENABLE_DEBUGGER if (acpi_in_debugger) { kdb_printf("%s", buffer); } else { printk("%s", buffer); } #else printk("%s", buffer); #endif } static void acpi_table_taint(struct acpi_table_header *table) { pr_warn(PREFIX "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", table->signature, table->oem_table_id); add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); } acpi_status acpi_os_table_override(struct acpi_table_header * existing_table, struct acpi_table_header ** new_table) { if (!existing_table || !new_table) return AE_BAD_PARAMETER; *new_table = NULL; #ifdef CONFIG_ACPI_CUSTOM_DSDT if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header *)AmlCode; #endif if (*new_table != NULL) acpi_table_taint(existing_table); return AE_OK; } acpi_status acpi_os_physical_table_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *table_length) { #ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE *table_length = 0; *address = 0; return AE_OK; #else int table_offset = 0; struct acpi_table_header *table; *table_length = 0; *address = 0; if (!acpi_tables_addr) return AE_OK; do { if (table_offset + ACPI_HEADER_SIZE > all_tables_size) { WARN_ON(1); return AE_OK; } table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return AE_OK; } table_offset += table->length; if (memcmp(existing_table->signature, table->signature, 4)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); continue; } /* Only override tables with matching oem id */ if (memcmp(table->oem_table_id, existing_table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); continue; } table_offset -= table->length; *table_length = table->length; acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); *address = acpi_tables_addr + table_offset; break; } while (table_offset + ACPI_HEADER_SIZE < all_tables_size); if (*address != 0) acpi_table_taint(existing_table); return AE_OK; #endif } static struct osi_linux { unsigned int enable:1; unsigned int dmi:1; unsigned int cmdline:1; unsigned int default_disabling:1; } osi_linux = {0, 0, 0, 0}; #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ #define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */ struct osi_setup_entry { char string[OSI_STRING_LENGTH_MAX]; bool enable; }; static struct osi_setup_entry osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = { {"Module Device", true}, {"Processor Device", true}, {"3.0 _SCP Extensions", true}, {"Processor Aggregator Device", true}, }; void __init acpi_osi_setup(char *str) { struct osi_setup_entry *osi; bool enable = true; int i; if (!acpi_gbl_create_osi_method) return; if (str == NULL || *str == '\0') { printk(KERN_INFO PREFIX "_OSI method disabled\n"); acpi_gbl_create_osi_method = FALSE; return; } if (*str == '!') { str++; if (*str == '\0') { osi_linux.default_disabling = 1; return; } else if (*str == '*') { acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS); for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { osi = &osi_setup_entries[i]; osi->enable = false; } return; } enable = false; } for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { osi = &osi_setup_entries[i]; if (!strcmp(osi->string, str)) { osi->enable = enable; break; } else if (osi->string[0] == '\0') { osi->enable = enable; strncpy(osi->string, str, OSI_STRING_LENGTH_MAX); break; } } } static void __init set_osi_linux(unsigned int enable) { if (osi_linux.enable != enable) osi_linux.enable = enable; if (osi_linux.enable) acpi_osi_setup("Linux"); else acpi_osi_setup("!Linux"); return; } void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) { printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); if (enable == -1) return; osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ set_osi_linux(enable); return; } acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) { void *sem = (void*)handle; if (!acpi_os_initialized) return AE_OK; if (!sem || (units < 1)) return AE_BAD_PARAMETER; if (units > 1) return AE_SUPPORT; ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); return AE_OK; } acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) { void *sem = (void*)handle; if (!acpi_os_initialized) return AE_OK; if (!sem || (units < 1)) return AE_BAD_PARAMETER; if (units > 1) return AE_SUPPORT; ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle, units)); // up(sem); return AE_OK; } acpi_status __init acpi_os_initialize(void) { // acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); // acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); // acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); // acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { /* * Use acpi_os_map_generic_address to pre-map the reset * register if it's in system memory. */ int rv; rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); } acpi_os_initialized = true; return AE_OK; } acpi_status __init acpi_os_initialize1(void) { // kacpid_wq = alloc_workqueue("kacpid", 0, 1); // kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); // kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); // BUG_ON(!kacpid_wq); // BUG_ON(!kacpi_notify_wq); // BUG_ON(!kacpi_hotplug_wq); // acpi_install_interface_handler(acpi_osi_handler); // acpi_osi_setup_late(); return AE_OK; } acpi_status acpi_os_delete_semaphore(acpi_handle handle) { // void *sem = (void*)handle; // if (!sem) // return AE_BAD_PARAMETER; // kfree(sem); // sem = NULL; return AE_OK; } acpi_status acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * out_handle) { *out_handle = (acpi_handle) 1; return (AE_OK); } acpi_status acpi_os_create_mutex(acpi_handle * handle) { struct mutex *mtx = NULL; mtx = kzalloc(sizeof(struct mutex),0); if (!mtx) return AE_NO_MEMORY; mutex_init(mtx); *handle = (acpi_handle *) mtx; return AE_OK; } void acpi_os_release_mutex(acpi_mutex handle) { struct mutex *mtx = (struct mutex*)handle; if (!acpi_os_initialized) return; mutex_unlock(mtx); } acpi_status acpi_os_acquire_mutex(acpi_mutex handle, u16 timeout) { struct mutex *mtx = (struct mutex*)handle; if (!acpi_os_initialized) return AE_OK; mutex_lock(mtx); return AE_OK; } void acpi_os_delete_mutex(acpi_mutex handle) { struct mutex *mtx = (struct mutex*)handle; kfree(mtx); }; acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) { acpi_cpu_flags flags; spin_lock_irqsave(lockp, flags); return flags; } void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) { spin_unlock_irqrestore(lockp, flags); } acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { case ACPI_SIGNAL_FATAL: printk(KERN_ERR PREFIX "Fatal opcode executed\n"); break; case ACPI_SIGNAL_BREAKPOINT: /* * AML Breakpoint * ACPI spec. says to treat it as a NOP unless * you are debugging. So if/when we integrate * AML debugger into the kernel debugger its * hook will go here. But until then it is * not useful to print anything on breakpoints. */ break; default: break; } return AE_OK; } void acpi_os_sleep(u64 ms) { msleep(ms); } void acpi_os_stall(u32 us) { while (us) { u32 delay = 1000; if (delay > us) delay = us; udelay(delay); // touch_nmi_watchdog(); us -= delay; } } void msleep(unsigned int msecs) { msecs /= 10; if(!msecs) msecs = 1; __asm__ __volatile__ ( "call *__imp__Delay" ::"b" (msecs)); __asm__ __volatile__ ( "":::"ebx"); }; acpi_status acpi_os_execute(acpi_execute_type type, acpi_osd_exec_callback function, void *context) { return AE_OK; } u64 acpi_os_get_timer(void) { u64 time_ns = ktime_to_ns(ktime_get()); do_div(time_ns, 100); return time_ns; } ktime_t ktime_get(void) { ktime_t t; t.tv64 = GetClockNs(); return t; } void __delay(unsigned long loops) { asm volatile( "test %0,%0\n" "jz 3f\n" "jmp 1f\n" ".align 16\n" "1: jmp 2f\n" ".align 16\n" "2: dec %0\n" " jnz 2b\n" "3: dec %0\n" : /* we don't need output */ : "a" (loops) ); } inline void __const_udelay(unsigned long xloops) { int d0; xloops *= 4; asm("mull %%edx" : "=d" (xloops), "=&a" (d0) : "1" (xloops), "" (loops_per_jiffy * (HZ/4))); __delay(++xloops); } void __udelay(unsigned long usecs) { __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ } #define acpi_rev_override false #define ACPI_MAX_OVERRIDE_LEN 100 static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN]; acpi_status acpi_os_predefined_override(const struct acpi_predefined_names *init_val, char **new_val) { if (!init_val || !new_val) return AE_BAD_PARAMETER; *new_val = NULL; if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) { printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n", acpi_os_name); *new_val = acpi_os_name; } if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) { printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n"); *new_val = (char *)5; } return AE_OK; }