1 /*
2  *  acpi_osl.c - OS-dependent functions ($Revision: 83 $)
3  *
4  *  Copyright (C) 2000       Andrew Henroid
5  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
6  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7  *
8  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
22  *
23  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24  *
25  */
26 #include <asm/io.h>
27 #include <xen/init.h>
28 #include <xen/pfn.h>
29 #include <xen/types.h>
30 #include <xen/errno.h>
31 #include <xen/acpi.h>
32 #include <xen/numa.h>
33 #include <acpi/acmacros.h>
34 #include <acpi/acpiosxf.h>
35 #include <acpi/platform/aclinux.h>
36 #include <xen/spinlock.h>
37 #include <xen/domain_page.h>
38 #include <xen/efi.h>
39 #include <xen/vmap.h>
40 
41 #define _COMPONENT		ACPI_OS_SERVICES
42 ACPI_MODULE_NAME("osl")
43 
44 #ifdef CONFIG_ACPI_CUSTOM_DSDT
45 #include CONFIG_ACPI_CUSTOM_DSDT_FILE
46 #endif
47 
acpi_os_printf(const char * fmt,...)48 void __init acpi_os_printf(const char *fmt, ...)
49 {
50 	va_list args;
51 	va_start(args, fmt);
52 	acpi_os_vprintf(fmt, args);
53 	va_end(args);
54 }
55 
acpi_os_vprintf(const char * fmt,va_list args)56 void __init acpi_os_vprintf(const char *fmt, va_list args)
57 {
58 	static char buffer[512];
59 
60 	vsnprintf(buffer, sizeof(buffer), fmt, args);
61 
62 	printk("%s", buffer);
63 }
64 
65 acpi_physical_address __initdata rsdp_hint;
66 
acpi_os_get_root_pointer(void)67 acpi_physical_address __init acpi_os_get_root_pointer(void)
68 {
69 	if (rsdp_hint)
70 		return rsdp_hint;
71 
72 	if (efi_enabled(EFI_BOOT)) {
73 		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
74 			return efi.acpi20;
75 		else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
76 			return efi.acpi;
77 		else {
78 			printk(KERN_ERR PREFIX
79 			       "System description tables not found\n");
80 			return 0;
81 		}
82 	} else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) {
83 		acpi_physical_address pa = 0;
84 
85 		acpi_find_root_pointer(&pa);
86 		return pa;
87 	}
88 
89 	return 0;
90 }
91 
92 void __iomem *
acpi_os_map_memory(acpi_physical_address phys,acpi_size size)93 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
94 {
95 	if (system_state >= SYS_STATE_boot) {
96 		mfn_t mfn = _mfn(PFN_DOWN(phys));
97 		unsigned int offs = phys & (PAGE_SIZE - 1);
98 
99 		/* The low first Mb is always mapped on x86. */
100 		if (IS_ENABLED(CONFIG_X86) && !((phys + size - 1) >> 20))
101 			return __va(phys);
102 		return __vmap(&mfn, PFN_UP(offs + size), 1, 1,
103 			      ACPI_MAP_MEM_ATTR, VMAP_DEFAULT) + offs;
104 	}
105 	return __acpi_map_table(phys, size);
106 }
107 
acpi_os_unmap_memory(void __iomem * virt,acpi_size size)108 void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
109 {
110 	if (IS_ENABLED(CONFIG_X86) &&
111 	    (unsigned long)virt >= DIRECTMAP_VIRT_START &&
112 	    (unsigned long)virt < DIRECTMAP_VIRT_END) {
113 		ASSERT(!((__pa(virt) + size - 1) >> 20));
114 		return;
115 	}
116 
117 	if (system_state >= SYS_STATE_boot)
118 		vunmap((void *)((unsigned long)virt & PAGE_MASK));
119 }
120 
acpi_os_read_port(acpi_io_address port,u32 * value,u32 width)121 acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
122 {
123 	u32 dummy;
124 
125 	if (!value)
126 		value = &dummy;
127 
128 	*value = 0;
129 	if (width <= 8) {
130 		*(u8 *) value = inb(port);
131 	} else if (width <= 16) {
132 		*(u16 *) value = inw(port);
133 	} else if (width <= 32) {
134 		*(u32 *) value = inl(port);
135 	} else {
136 		BUG();
137 	}
138 
139 	return AE_OK;
140 }
141 
acpi_os_write_port(acpi_io_address port,u32 value,u32 width)142 acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
143 {
144 	if (width <= 8) {
145 		outb(value, port);
146 	} else if (width <= 16) {
147 		outw(value, port);
148 	} else if (width <= 32) {
149 		outl(value, port);
150 	} else {
151 		BUG();
152 	}
153 
154 	return AE_OK;
155 }
156 
157 acpi_status
acpi_os_read_memory(acpi_physical_address phys_addr,u32 * value,u32 width)158 acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
159 {
160 	u32 dummy;
161 	void __iomem *virt_addr = acpi_os_map_memory(phys_addr, width >> 3);
162 
163 	if (!virt_addr)
164 		return AE_ERROR;
165 
166 	if (!value)
167 		value = &dummy;
168 
169 	switch (width) {
170 	case 8:
171 		*(u8 *) value = readb(virt_addr);
172 		break;
173 	case 16:
174 		*(u16 *) value = readw(virt_addr);
175 		break;
176 	case 32:
177 		*(u32 *) value = readl(virt_addr);
178 		break;
179 	default:
180 		BUG();
181 	}
182 
183 	acpi_os_unmap_memory(virt_addr, width >> 3);
184 
185 	return AE_OK;
186 }
187 
188 acpi_status
acpi_os_write_memory(acpi_physical_address phys_addr,u32 value,u32 width)189 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
190 {
191 	void __iomem *virt_addr = acpi_os_map_memory(phys_addr, width >> 3);
192 
193 	if (!virt_addr)
194 		return AE_ERROR;
195 
196 	switch (width) {
197 	case 8:
198 		writeb(value, virt_addr);
199 		break;
200 	case 16:
201 		writew(value, virt_addr);
202 		break;
203 	case 32:
204 		writel(value, virt_addr);
205 		break;
206 	default:
207 		BUG();
208 	}
209 
210 	acpi_os_unmap_memory(virt_addr, width >> 3);
211 
212 	return AE_OK;
213 }
214 
215 #define is_xmalloc_memory(ptr) ((unsigned long)(ptr) & (PAGE_SIZE - 1))
216 
acpi_os_alloc_memory(size_t sz)217 void *__init acpi_os_alloc_memory(size_t sz)
218 {
219 	void *ptr;
220 
221 	if (system_state == SYS_STATE_early_boot)
222 		return mfn_to_virt(mfn_x(alloc_boot_pages(PFN_UP(sz), 1)));
223 
224 	ptr = xmalloc_bytes(sz);
225 	ASSERT(!ptr || is_xmalloc_memory(ptr));
226 	return ptr;
227 }
228 
acpi_os_zalloc_memory(size_t sz)229 void *__init acpi_os_zalloc_memory(size_t sz)
230 {
231 	void *ptr;
232 
233 	if (system_state != SYS_STATE_early_boot) {
234 		ptr = xzalloc_bytes(sz);
235 		ASSERT(!ptr || is_xmalloc_memory(ptr));
236 		return ptr;
237 	}
238 	ptr = acpi_os_alloc_memory(sz);
239 	return ptr ? memset(ptr, 0, sz) : NULL;
240 }
241 
acpi_os_free_memory(void * ptr)242 void __init acpi_os_free_memory(void *ptr)
243 {
244 	if (is_xmalloc_memory(ptr))
245 		xfree(ptr);
246 	else if (ptr && system_state == SYS_STATE_early_boot)
247 		init_boot_pages(__pa(ptr), __pa(ptr) + PAGE_SIZE);
248 }
249