aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/acpi/acpi.c
blob: 2f1c29f38b1692ac034ec1abd757c5ec66221f1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Important specification: https://uefi.org/sites/default/files/resources/ACPI_6_2.pdf
// HPET: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf

#include <stddef.h>
#include <system.h>
#include <multiboot.h>
#include <io/io.h>
#include <lib/lib.h>
#include <lib/stdlib.h>
#include <lib/stdio.h>
#include <acpi/acpi.h>
#include <memory/paging.h>
#include <memory/alloc.h>

struct rsdt *rsdt;
struct fadt *fadt;
struct hpet *hpet;
struct madt *madt;

int check_sum(struct sdt_header *header)
{
	u8 sum = 0;

	for (u32 i = 0; i < header->length; i++)
		sum += ((char *)header)[i];

	return sum == 0;
}

void acpi_init(struct rsdp *rsdp)
{
	// TODO: Fix ACPI table discovering (HPET & MADT missing)
	// TODO: Fix ACPI breaking VESA (why?!)

	struct sdt_header *header = (struct sdt_header *)kmalloc(sizeof(struct sdt_header));
	rsdt = (struct rsdt *)kmalloc(sizeof(struct rsdt));
	fadt = (struct fadt *)kmalloc(sizeof(struct fadt));
	hpet = (struct hpet *)kmalloc(sizeof(struct hpet));
	madt = (struct madt *)kmalloc(sizeof(struct madt));

	if (strncmp(rsdp->signature, "RSD PTR ", 8) == 0) {
		memcpy(rsdt, rsdp->rsdt_address, sizeof(struct rsdt) + 32);
		debug("Found RSDT");
		if (!check_sum((struct sdt_header *)rsdt)) {
			warn("Corrupted RSDT!");
		} else {
			u32 *pointer = (u32 *)(rsdt + 1);
			u32 *end = (u32 *)((u8 *)rsdt + rsdt->header.length);

			while (pointer < end) {
				u32 address = *pointer++;
				memcpy(header, (void *)address, sizeof(struct sdt_header));

				if (strncmp(header->signature, "FACP", 4) == 0) {
					debug("Found FADT");
					memcpy(fadt, (void *)address, sizeof(struct fadt));
					if (!check_sum((struct sdt_header *)fadt))
						warn("Corrupted FADT!");
				} else if (strncmp(header->signature, "HPET", 4) == 0) {
					debug("Found HPET");
					memcpy(hpet, (void *)address, sizeof(struct hpet));
					if (!check_sum((struct sdt_header *)hpet))
						warn("Corrupted HPET!");
				} else if (strncmp(header->signature, "APIC", 4) == 0) {
					debug("Found MADT");
					memcpy(madt, (void *)address, sizeof(struct madt));
					if (!check_sum((struct sdt_header *)madt))
						warn("Corrupted MADT!");
				}
			}
		}
	} else {
		warn("Wrong RSD signature!");
	}
	kfree(header);
}

void acpi_old_init(struct multiboot_tag_old_acpi *tag)
{
	// acpi_init((struct rsdp *)tag->rsdp);
}

void acpi_new_init(struct multiboot_tag_new_acpi *tag)
{
	// acpi_init((struct rsdp *)tag->rsdp);
}

void acpi_poweroff()
{
	// TODO: Add APCI poweroff support
	cli();
	outw(0x604, 0x2000); // QEMU
	outw(0xB004, 0x2000); // Bochs
	outw(0x4004, 0x3400); // VirtualBox
	halt_loop();
}

void reboot()
{
	cli();
	if (fadt->header.revision >= 2 && fadt->flags.reset_support) {
		debug("Reset support!");
		outb(fadt->reset_reg.address, fadt->reset_value);
		halt_loop();
	} else {
		u8 good = 0x02;
		while (good & 0x02)
			good = inb(0x64);
		outb(0x64, 0xFE);
		halt_loop();
	}
}