0% found this document useful (0 votes)
23 views

Acpi C

This document describes the initialization of the Advanced Configuration and Power Interface (ACPI) on a system and issuing a shutdown command via ACPI. It defines functions to search the BIOS memory for ACPI tables, validate the contents, extract power state values from the Differentiated System Description Table (DSDT), enable ACPI if needed, and send the shutdown command bits to the Power Management Timer registers. The goal is to power off the system in a standard way defined by the ACPI specification.

Uploaded by

thatsmeharsha17
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views

Acpi C

This document describes the initialization of the Advanced Configuration and Power Interface (ACPI) on a system and issuing a shutdown command via ACPI. It defines functions to search the BIOS memory for ACPI tables, validate the contents, extract power state values from the Differentiated System Description Table (DSDT), enable ACPI if needed, and send the shutdown command bits to the Power Management Timer registers. The goal is to power off the system in a standard way defined by the ACPI specification.

Uploaded by

thatsmeharsha17
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

1 /**

2 * https://wiki.osdev.org/Shutdown
3 * https://elixir.bootlin.com/linux/2.3.35/source/arch/i386/kernel/acpi.c#L879
4 * https://forum.osdev.org/viewtopic.php?t=16990
5 */
6 #include "acpi.h"
7 #include "libc/memory.h"
8 #include "libc/pio.h"
9
10 // global variables
11 static b16 SLP_TYPa;
12 static b16 SLP_TYPb;
13 static struct acpi_fadt *fadt;
14
15 // initialization
16 static struct acpi_rsdp *search_RSDP_from_BIOS_memory(void);
17 static struct acpi_rsdt *fetch_and_validate_RSDT_from_RSDP(struct acpi_rsdp *rsdp);
18 static struct acpi_fadt *search_FADT_from_RSDT(struct acpi_rsdt *rsdt);
19 static struct acpi_dsdt *fetch_and_validate_DSDT_from_FADT(struct acpi_fadt *fadt);
20 static byte *search_S5_from_DSDT(struct acpi_dsdt *dsdt);
21 static bool is_valid_S5_address(byte *S5_address);
22 static void extract_SLP_TYPa_and_SLP_TYPb(byte *S5_address, b16 *SLP_TYPa_ptr, b16
*SLP_TYPb_ptr);
23
24 STATUS acpi_init(void)
25 {
26 struct acpi_rsdp *rsdp;
27 struct acpi_rsdt *rsdt;
28 struct acpi_dsdt *dsdt;
29 byte *S5_address;
30
31 if ((rsdp = search_RSDP_from_BIOS_memory()) == NULL)
32 {
33 return ENODEV;
34 }
35
36 if ((rsdt = fetch_and_validate_RSDT_from_RSDP(rsdp)) == NULL)
37 {
38 return ENODEV;
39 }
40
41 if ((fadt = search_FADT_from_RSDT(rsdt)) == NULL)
42 {
43 return ENODEV;
44 }
45
46 if ((dsdt = fetch_and_validate_DSDT_from_FADT(fadt)) == NULL)
47 {
48 return ENODEV;
49 }
50
51 /**
52 * bytecode of the \_S5 object
53 * -----------------------------------------
54 * / | (optional) | | point by S5_address
55 * AML code | NameOP | '\' | '_' | 'S' | '5' | '_'
56 * byte value | 08 | 5A | 5F | 53 | 35 | 5F
57
58 * ----------------------------------------------------------------------------
-------------------------------
59 * | | | ( SLP_TYPa ) | ( SLP_TYPb ) | (
Reserved ) | (Reserved )
60 * PackageOP | PkgLength | NumElements | byteprefix Num | byteprefix Num |
byteprefix Num | byteprefix Num
61 * 12 | 0A | 04 | 0A 05 | 0A 05 | 0A
05 | 0A 05
62
63 * ----this-structure-was-also-seen----------------------
64 * PackageOP | PkgLength | NumElements |
65 * 12 | 06 | 04 | 00 00 00 00
66 */
67 if ((S5_address = search_S5_from_DSDT(dsdt)) == NULL)
68 {
69 return ENODEV;
70 }
71
72 if (!is_valid_S5_address(S5_address))
73 {
74 return EACCERT;
75 }
76
77 extract_SLP_TYPa_and_SLP_TYPb(S5_address, &SLP_TYPa, &SLP_TYPb);
78
79 return SUCCESS;
80 }
81
82 static struct acpi_rsdp *search_RSDP_from_BIOS_memory(void)
83 {
84 nat32 i = 0;
85 struct acpi_rsdp *rsdp;
86 for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16)
87 {
88 rsdp = (struct acpi_rsdp *)i;
89 if (rsdp->signature[0] == ACPI_RSDP1_SIG && rsdp->signature[1] ==
ACPI_RSDP2_SIG)
90 {
91 return rsdp;
92 }
93 }
94 return NULL;
95 }
96
97 static struct acpi_rsdt *fetch_and_validate_RSDT_from_RSDP(struct acpi_rsdp *rsdp)
98 {
99 struct acpi_rsdt *rsdt = rsdp->rsdt;
100 if (rsdt && rsdt->header.signature == ACPI_RSDT_SIG)
101 {
102 return rsdt;
103 }
104 return NULL;
105 }
106
107 struct acpi_fadt *search_FADT_from_RSDT(struct acpi_rsdt *rsdt)
108 {
109 nat32 sdt_entry_index;
110 nat32 sdt_entries_count = (nat32)((rsdt->header.length - sizeof(rsdt->header)) /
sizeof(struct acpi_sdt_header *));
111 for (sdt_entry_index = 0; sdt_entry_index < sdt_entries_count;
sdt_entry_index++)
112 {
113 struct acpi_sdt_header *sdt_entry = rsdt->sdt_ptrs[sdt_entry_index];
114 if (sdt_entry && sdt_entry->signature == ACPI_FADT_SIG)
115 {
116 return (struct acpi_fadt *)sdt_entry;
117 }
118 }
119 return NULL;
120 }
121
122 static struct acpi_dsdt *fetch_and_validate_DSDT_from_FADT(struct acpi_fadt *fadt)
123 {
124 struct acpi_dsdt *dsdt = fadt->dsdt;
125 if (dsdt && dsdt->header.signature == ACPI_DSDT_SIG)
126 {
127 return dsdt;
128 }
129 return NULL;
130 }
131
132 static byte *search_S5_from_DSDT(struct acpi_dsdt *dsdt)
133 {
134 byte *S5_address = dsdt->aml_code;
135 nat32 aml_code_length = dsdt->header.length - sizeof(dsdt->header);
136 while (aml_code_length-- > 0)
137 {
138 if (memcmp(S5_address, (byte *)("_S5_"), 4) == 0)
139 {
140 return S5_address;
141 }
142 ++S5_address;
143 }
144 return NULL;
145 }
146
147 static bool is_valid_S5_address(byte *S5_address)
148 {
149 return (*(S5_address - 1) == 0x08 || (*(S5_address - 2) == 0x08 && *(S5_address
- 1) == '\\')) && *(S5_address + 4) == 0x12;
150 }
151
152 #define ACPI_SLP_TYP_SHIFT 10
153 static void extract_SLP_TYPa_and_SLP_TYPb(byte *S5_address, b16 *SLP_TYPa_ptr, b16
*SLP_TYPb_ptr)
154 {
155 S5_address += 5;
156 S5_address += ((*S5_address & 0xC0) >> 6) + 2; // calculate PkgLength size
157
158 if (*S5_address == 0x0A)
159 S5_address++; // skip byteprefix
160 *SLP_TYPa_ptr = *(S5_address) << ACPI_SLP_TYP_SHIFT;
161 S5_address++;
162
163 if (*S5_address == 0x0A)
164 S5_address++; // skip byteprefix
165 *SLP_TYPb_ptr = *(S5_address) << ACPI_SLP_TYP_SHIFT;
166 }
167
168 // power off command
169 static STATUS ensure_acpi_is_enabled(struct acpi_fadt *fadt);
170 static void sendShutdownCommand(struct acpi_fadt *fadt, b16 SLP_TYPa, b16 SLP_TYPb);
171 STATUS acpi_power_off(void)
172 {
173 STATUS status;
174 status = ensure_acpi_is_enabled(fadt);
175 if (status != SUCCESS)
176 {
177 return status;
178 }
179 sendShutdownCommand(fadt, SLP_TYPa, SLP_TYPb);
180 return SUCCESS;
181 }
182
183 static bool acpi_is_enabled(struct acpi_fadt *fadt);
184 static void acpi_enable_SCI(struct acpi_fadt *fadt);
185 static STATUS ensure_acpi_is_enabled(struct acpi_fadt *fadt)
186 {
187 nat32 attempts = 5000;
188 if (!acpi_is_enabled(fadt))
189 {
190 acpi_enable_SCI(fadt);
191 while (!acpi_is_enabled(fadt) && attempts-- > 0)
192 {
193 io_wait();
194 }
195 if (!acpi_is_enabled(fadt))
196 {
197 return EACCERT;
198 }
199 }
200 return SUCCESS;
201 }
202
203 #define ACPI_SCI_EN 0x0001
204 static void acpi_enable_SCI(struct acpi_fadt *fadt)
205 {
206 if (fadt->smi_cmd)
207 out_byte((nat16)fadt->smi_cmd, fadt->acpi_enable);
208 }
209
210 static word acpi_read_pm1_control(struct acpi_fadt *fadt);
211 static bool acpi_is_enabled(struct acpi_fadt *fadt)
212 {
213 return ((acpi_read_pm1_control(fadt) & ACPI_SCI_EN) ? true : false);
214 }
215
216 static word acpi_read_pm1_control(struct acpi_fadt *fadt)
217 {
218 word value = 0;
219 if (fadt->pm1a_cnt)
220 value = in_b16(fadt->pm1a_cnt);
221 if (fadt->pm1b_cnt)
222 value |= in_b16(fadt->pm1b_cnt);
223 return value;
224 }
225
226 #define ACPI_SLP_TYP_MASK 0x1c00
227 #define ACPI_SLP_EN 0x2000 // = 1 << 13
228 static void sendShutdownCommand(struct acpi_fadt *fadt, b16 SLP_TYPa, b16 SLP_TYPb)
229 {
230 b16 value = in_b16(fadt->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
231 out_b16(fadt->pm1a_cnt, value | SLP_TYPa | ACPI_SLP_EN);
232 if (fadt->pm1b_cnt != 0)
233 {
234 value = in_b16(fadt->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
235 out_b16(fadt->pm1b_cnt, value | SLP_TYPb | ACPI_SLP_EN);
236 }
237 }

You might also like