1 2 #include <string.h> 3 4 #include "kernel/kernel.h" 5 #include "acpi.h" 6 #include "arch_proto.h" 7 8 typedef int ((* acpi_read_t)(phys_bytes addr, void * buff, size_t size)); 9 10 struct acpi_rsdp acpi_rsdp; 11 12 static acpi_read_t read_func; 13 14 #define MAX_RSDT 35 /* ACPI defines 35 signatures */ 15 #define SLP_EN_CODE (1 << 13) /* ACPI SLP_EN_CODE code */ 16 #define AMI_PACKAGE_OP_CODE (0x12) 17 #define AMI_NAME_OP_CODE (0x8) 18 #define AMI_BYTE_PREFIX_CODE (0xA) 19 #define AMI_PACKAGE_LENGTH_ENCODING_BITS_MASK (0xC0) 20 #define AMI_PACKAGE_LENGTH_ENCODING_BITS_SHIFT (6) 21 #define AMI_MIN_PACKAGE_LENGTH (1) 22 #define AMI_NUM_ELEMENTS_LENGTH (1) 23 #define AMI_SLP_TYPA_SHIFT (10) 24 #define AMI_SLP_TYPB_SHIFT (10) 25 #define AMI_S5_NAME_OP_OFFSET_1 (-1) 26 #define AMI_S5_NAME_OP_OFFSET_2 (-2) 27 #define AMI_S5_PACKAGE_OP_OFFSET (4) 28 #define AMI_S5_PACKET_LENGTH_OFFSET (5) 29 30 static struct acpi_rsdt { 31 struct acpi_sdt_header hdr; 32 u32_t data[MAX_RSDT]; 33 } rsdt; 34 35 static struct { 36 char signature [ACPI_SDT_SIGNATURE_LEN + 1]; 37 size_t length; 38 } sdt_trans[MAX_RSDT]; 39 40 static int sdt_count; 41 static u16_t pm1a_cnt_blk = 0; 42 static u16_t pm1b_cnt_blk = 0; 43 static u16_t slp_typa = 0; 44 static u16_t slp_typb = 0; 45 46 static int acpi_check_csum(struct acpi_sdt_header * tb, size_t size) 47 { 48 u8_t total = 0; 49 int i; 50 for (i = 0; i < size; i++) 51 total += ((unsigned char *)tb)[i]; 52 return total == 0 ? 0 : -1; 53 } 54 55 static int acpi_check_signature(const char * orig, const char * match) 56 { 57 return strncmp(orig, match, ACPI_SDT_SIGNATURE_LEN); 58 } 59 60 static u32_t acpi_phys2vir(u32_t p) 61 { 62 if(!vm_running) { 63 DEBUGEXTRA(("acpi: returning 0x%lx as vir addr\n", p)); 64 return p; 65 } 66 panic("acpi: can't get virtual address of arbitrary physical address"); 67 } 68 69 static int acpi_phys_copy(phys_bytes phys, void *target, size_t len) 70 { 71 if(!vm_running) { 72 memcpy(target, (void *) phys, len); 73 return 0; 74 } 75 panic("can't acpi_phys_copy with vm"); 76 } 77 78 static int acpi_read_sdt_at(phys_bytes addr, 79 struct acpi_sdt_header * tb, 80 size_t size, 81 const char * name) 82 { 83 struct acpi_sdt_header hdr; 84 85 /* if NULL is supplied, we only return the size of the table */ 86 if (tb == NULL) { 87 if (read_func(addr, &hdr, sizeof(struct acpi_sdt_header))) { 88 printf("ERROR acpi cannot read %s header\n", name); 89 return -1; 90 } 91 92 return hdr.length; 93 } 94 95 if (read_func(addr, tb, sizeof(struct acpi_sdt_header))) { 96 printf("ERROR acpi cannot read %s header\n", name); 97 return -1; 98 } 99 100 if (acpi_check_signature(tb->signature, name)) { 101 printf("ERROR acpi %s signature does not match\n", name); 102 return -1; 103 } 104 105 if (size < tb->length) { 106 printf("ERROR acpi buffer too small for %s\n", name); 107 return -1; 108 } 109 110 if (read_func(addr, tb, size)) { 111 printf("ERROR acpi cannot read %s\n", name); 112 return -1; 113 } 114 115 if (acpi_check_csum(tb, tb->length)) { 116 printf("ERROR acpi %s checksum does not match\n", name); 117 return -1; 118 } 119 120 return tb->length; 121 } 122 123 phys_bytes acpi_get_table_base(const char * name) 124 { 125 int i; 126 127 for(i = 0; i < sdt_count; i++) { 128 if (strncmp(name, sdt_trans[i].signature, 129 ACPI_SDT_SIGNATURE_LEN) == 0) 130 return (phys_bytes) rsdt.data[i]; 131 } 132 133 return (phys_bytes) NULL; 134 } 135 136 size_t acpi_get_table_length(const char * name) 137 { 138 int i; 139 140 for(i = 0; i < sdt_count; i++) { 141 if (strncmp(name, sdt_trans[i].signature, 142 ACPI_SDT_SIGNATURE_LEN) == 0) 143 return sdt_trans[i].length; 144 } 145 146 return 0; 147 } 148 149 static void * acpi_madt_get_typed_item(struct acpi_madt_hdr * hdr, 150 unsigned char type, 151 unsigned idx) 152 { 153 u8_t * t, * end; 154 int i; 155 156 t = (u8_t *) hdr + sizeof(struct acpi_madt_hdr); 157 end = (u8_t *) hdr + hdr->hdr.length; 158 159 i = 0; 160 while(t < end) { 161 if (type == ((struct acpi_madt_item_hdr *) t)->type) { 162 if (i == idx) 163 return t; 164 else 165 i++; 166 } 167 t += ((struct acpi_madt_item_hdr *) t)->length; 168 } 169 170 return NULL; 171 } 172 173 #if 0 174 static void * acpi_madt_get_item(struct acpi_madt_hdr * hdr, 175 unsigned idx) 176 { 177 u8_t * t, * end; 178 int i; 179 180 t = (u8_t *) hdr + sizeof(struct acpi_madt_hdr); 181 end = (u8_t *) hdr + hdr->hdr.length; 182 183 for(i = 0 ; i <= idx && t < end; i++) { 184 if (i == idx) 185 return t; 186 t += ((struct acpi_madt_item_hdr *) t)->length; 187 } 188 189 return NULL; 190 } 191 #endif 192 193 static int acpi_rsdp_test(void * buff) 194 { 195 struct acpi_rsdp * rsdp = (struct acpi_rsdp *) buff; 196 197 if (!platform_tbl_checksum_ok(buff, 20)) 198 return 0; 199 if (strncmp(rsdp->signature, "RSD PTR ", 8)) 200 return 0; 201 202 return 1; 203 } 204 205 static int get_acpi_rsdp(void) 206 { 207 u16_t ebda; 208 /* 209 * Read 40:0Eh - to find the starting address of the EBDA. 210 */ 211 acpi_phys_copy (0x40E, &ebda, sizeof(ebda)); 212 if (ebda) { 213 ebda <<= 4; 214 if(platform_tbl_ptr(ebda, ebda + 0x400, 16, &acpi_rsdp, 215 sizeof(acpi_rsdp), &machine.acpi_rsdp, 216 acpi_rsdp_test)) 217 return 1; 218 } 219 220 /* try BIOS read only mem space */ 221 if(platform_tbl_ptr(0xE0000, 0x100000, 16, &acpi_rsdp, 222 sizeof(acpi_rsdp), &machine.acpi_rsdp, 223 acpi_rsdp_test)) 224 return 1; 225 226 machine.acpi_rsdp = 0; /* RSDP cannot be found at this address therefore 227 it is a valid negative value */ 228 return 0; 229 } 230 231 static void acpi_init_poweroff(void) 232 { 233 u8_t *ptr = NULL; 234 u8_t *start = NULL; 235 u8_t *end = NULL; 236 struct acpi_fadt_header *fadt_header = NULL; 237 struct acpi_rsdt * dsdt_header = NULL; 238 char *msg = NULL; 239 240 /* Everything used here existed since ACPI spec 1.0 */ 241 /* So we can safely use them */ 242 fadt_header = (struct acpi_fadt_header *) 243 acpi_phys2vir(acpi_get_table_base("FACP")); 244 if (fadt_header == NULL) { 245 msg = "Could not load FACP"; 246 goto exit; 247 } 248 249 dsdt_header = (struct acpi_rsdt *) 250 acpi_phys2vir((phys_bytes) fadt_header->dsdt); 251 if (dsdt_header == NULL) { 252 msg = "Could not load DSDT"; 253 goto exit; 254 } 255 256 pm1a_cnt_blk = fadt_header->pm1a_cnt_blk; 257 pm1b_cnt_blk = fadt_header->pm1b_cnt_blk; 258 259 ptr = start = (u8_t *) dsdt_header->data; 260 end = start + dsdt_header->hdr.length - 4; 261 262 /* See http://forum.osdev.org/viewtopic.php?t=16990 */ 263 /* for layout of \_S5 */ 264 while (ptr < end && memcmp(ptr, "_S5_", 4) != 0) 265 ptr++; 266 267 msg = "Could not read S5 data. Use default SLP_TYPa and SLP_TYPb"; 268 if (ptr >= end || ptr == start) 269 goto exit; 270 271 /* validate AML structure */ 272 if (*(ptr + AMI_S5_PACKAGE_OP_OFFSET) != AMI_PACKAGE_OP_CODE) 273 goto exit; 274 275 if ((ptr < start + (-AMI_S5_NAME_OP_OFFSET_2) || 276 (*(ptr + AMI_S5_NAME_OP_OFFSET_2) != AMI_NAME_OP_CODE || 277 *(ptr + AMI_S5_NAME_OP_OFFSET_2 + 1) != '\\')) && 278 *(ptr + AMI_S5_NAME_OP_OFFSET_1) != AMI_NAME_OP_CODE) 279 goto exit; 280 281 ptr += AMI_S5_PACKET_LENGTH_OFFSET; 282 if (ptr >= end) 283 goto exit; 284 285 /* package length */ 286 ptr += ((*ptr & AMI_PACKAGE_LENGTH_ENCODING_BITS_MASK) >> 287 AMI_PACKAGE_LENGTH_ENCODING_BITS_SHIFT) + 288 AMI_MIN_PACKAGE_LENGTH + AMI_NUM_ELEMENTS_LENGTH; 289 if (ptr >= end) 290 goto exit; 291 292 if (*ptr == AMI_BYTE_PREFIX_CODE) 293 ptr++; /* skip byte prefix */ 294 295 slp_typa = (*ptr) << AMI_SLP_TYPA_SHIFT; 296 297 ptr++; /* move to SLP_TYPb */ 298 if (*ptr == AMI_BYTE_PREFIX_CODE) 299 ptr++; /* skip byte prefix */ 300 301 slp_typb = (*ptr) << AMI_SLP_TYPB_SHIFT; 302 303 msg = "poweroff initialized"; 304 305 exit: 306 if (msg) { 307 DEBUGBASIC(("acpi: %s\n", msg)); 308 } 309 } 310 311 void acpi_init(void) 312 { 313 int s, i; 314 read_func = acpi_phys_copy; 315 316 if (!get_acpi_rsdp()) { 317 printf("WARNING : Cannot configure ACPI\n"); 318 return; 319 } 320 321 s = acpi_read_sdt_at(acpi_rsdp.rsdt_addr, (struct acpi_sdt_header *) &rsdt, 322 sizeof(struct acpi_rsdt), ACPI_SDT_SIGNATURE(RSDT)); 323 324 sdt_count = (s - sizeof(struct acpi_sdt_header)) / sizeof(u32_t); 325 326 for (i = 0; i < sdt_count; i++) { 327 struct acpi_sdt_header hdr; 328 int j; 329 if (read_func(rsdt.data[i], &hdr, sizeof(struct acpi_sdt_header))) { 330 printf("ERROR acpi cannot read header at 0x%x\n", 331 rsdt.data[i]); 332 return; 333 } 334 335 for (j = 0 ; j < ACPI_SDT_SIGNATURE_LEN; j++) 336 sdt_trans[i].signature[j] = hdr.signature[j]; 337 sdt_trans[i].signature[ACPI_SDT_SIGNATURE_LEN] = '\0'; 338 sdt_trans[i].length = hdr.length; 339 } 340 341 acpi_init_poweroff(); 342 } 343 344 struct acpi_madt_ioapic * acpi_get_ioapic_next(void) 345 { 346 static unsigned idx = 0; 347 static struct acpi_madt_hdr * madt_hdr; 348 349 struct acpi_madt_ioapic * ret; 350 351 if (idx == 0) { 352 madt_hdr = (struct acpi_madt_hdr *) 353 acpi_phys2vir(acpi_get_table_base("APIC")); 354 if (madt_hdr == NULL) 355 return NULL; 356 } 357 358 ret = (struct acpi_madt_ioapic *) 359 acpi_madt_get_typed_item(madt_hdr, ACPI_MADT_TYPE_IOAPIC, idx); 360 if (ret) 361 idx++; 362 363 return ret; 364 } 365 366 struct acpi_madt_lapic * acpi_get_lapic_next(void) 367 { 368 static unsigned idx = 0; 369 static struct acpi_madt_hdr * madt_hdr; 370 371 struct acpi_madt_lapic * ret; 372 373 if (idx == 0) { 374 madt_hdr = (struct acpi_madt_hdr *) 375 acpi_phys2vir(acpi_get_table_base("APIC")); 376 if (madt_hdr == NULL) 377 return NULL; 378 } 379 380 for (;;) { 381 ret = (struct acpi_madt_lapic *) 382 acpi_madt_get_typed_item(madt_hdr, 383 ACPI_MADT_TYPE_LAPIC, idx); 384 if (!ret) 385 break; 386 387 idx++; 388 389 /* report only usable CPUs */ 390 if (ret->flags & 1) 391 break; 392 } 393 394 return ret; 395 } 396 397 void __k_unpaged_acpi_poweroff(void) 398 { 399 /* NO OP poweroff symbol*/ 400 } 401 402 void acpi_poweroff(void) 403 { 404 if (pm1a_cnt_blk == 0) { 405 return; 406 } 407 outw(pm1a_cnt_blk, slp_typa | SLP_EN_CODE); 408 if (pm1b_cnt_blk != 0) { 409 outw(pm1b_cnt_blk, slp_typb | SLP_EN_CODE); 410 } 411 } 412