문서 편집 권한이 없습니다. 다음 이유를 확인해주세요: 요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다: 사용자. 문서의 원본을 보거나 복사할 수 있습니다. [[분류: 주변장치]] == 개요 == ACPI (Advanced Configuration and Power Interface)는 Power Management를 하기 위한 주변장치의 일종이다. ACPI는 운영체제가 어느정도의 파워가 지금 공급되고 있는지, CPU Fan speed, thermal zone, battery level과 같은 정보를 가져올 수 있게 한다. 또한 ACPI는 SMP, NUMA와 같은 Multiprocessing 정보또한 OS에게 제공한다. 이러한 정보는 MP floating table에도 존재하지만, Modern OS는 대부분 ACPI에서 먼저 SMP정보를 가져온다. == ACPI 접근 == ACPI는 BIOS 메모리에 저장되어 있다. [[EBDA]] BIOS메모리는 메모리 영역중 BIOS가 초기화 하는 부분이며, 0x40e, 혹은 0xffffff 아래에 ACPI가 저장되어 있다. ACPI는 두가지의 부분으로 구성되어 있는데, 첫 번쨰 부분은 OS가 부트과정에서 CPU configuration을 위해서 사용되는 정보가 저장되어 있는 부분과 (CPUs, APIC정보, NUMA 메모리 구조...) ACPI환경을 구성하고 있는 [[AML]]코드가 저장된 부분으로 구성된다. ACPI를 이용하기 위해서는 OS는 반드시 [[RSDP]]에 접근하여 정보를 가져와야 한다. RSDP가 발견되고, Verfication이 되면, RSDP (root system description pointer)은 RSDT(root system description table)에 대한 포인터를 가지고 있다. (XSDT _ eXtended System description table 는 최신 하드웨어에 내장됨) RSDT나 XSDT에는 해당하는 정보가 들어 있게 된다. XSDT는 RSDP를 호환할 수 있으며 RSDP의 rev필드에 0이면 rsdp1.0 아니면 XSDT를 사용하는 rsdp2.0이다. == 코드 == <syntaxhighlight lang=c> static struct acpi_rsdt* global_rsdt_pointer = NULL; static inline int check_rsdp(uint8_t *rsdp) { uint8_t check = 0; size_t size = sizeof(struct acpi_rsdp); if(!strncmp(rsdp, "RSD PTR ", 8)) { while(size--) check += (int8_t) *rsdp++; return check; } return -1; } static struct acpi_rsdp * get_rsdt() { // Get Extended BIOS data area pointer address uintptr_t ebda_pa = *(uint16_t *)P2V(0x40e); uint8_t *ebda = (uint8_t *)P2V(ebda_pa); uint8_t *ebda_cursor = ebda; // Get virtual address of EBDA printf("0x%x\n", ebda); while(ebda_cursor <= ebda + 0x400) { if(!check_rsdp(ebda_cursor)) { return (struct acpi_rsdp *)ebda_cursor; } ebda_cursor += 0x10; } ebda_cursor = (uint8_t *)0x000e0000; while(ebda_cursor < P2V(0x000fffff)) { if(!check_rsdp(ebda_cursor)) { return (struct acpi_rsdp *)ebda_cursor; } ebda_cursor += 0x10; } return NULL; } void acpi_init() { struct acpi_rsdp* rsdp = get_rsdt(); global_rsdt_pointer = (struct acpi_rsdt *)P2V(rsdp->rsdt & 0xffffffff); // This rsdt area is marked as 0x1 in multiboot2 mma flags. // Thus memory_init ignore this area as an allocation point. // Also physical memory manager ignore this area for managing. // So we have to set VMM to use this area. uint64_t addr = (uint64_t)P2V(global_rsdt_pointer); vmm_set_page(kernel_P4, addr, rsdp->rsdt, PAGE_PRESENT); vmm_activate(kernel_P4); } struct acpi_rsdt *acpi_get_rsdt(char signature[4]) { struct acpi_rsdt* rsdt = global_rsdt_pointer; if(!rsdt) { return NULL; } int entries = (rsdt->header.length - sizeof(rsdt->header)) / sizeof(uint32_t); for(int i = 0; i < entries; ++i) { struct acpi_rsdt_header *hdr = (struct acpi_rsdt_header *)P2V(rsdt->sdt[i]); if(!strncmp(hdr->signature, signature, 4)) { return hdr; } } return NULL; } </syntaxhighlight> ACPI 문서로 돌아갑니다.