| @@ -1,382 +1,385 @@ | | | @@ -1,382 +1,385 @@ |
1 | /* $NetBSD: efifdt.c,v 1.18 2019/08/01 13:11:16 jmcneill Exp $ */ | | 1 | /* $NetBSD: efifdt.c,v 1.19 2019/08/30 00:01:33 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2019 Jason R. Thorpe | | 4 | * Copyright (c) 2019 Jason R. Thorpe |
5 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> | | 5 | * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca> |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | | 15 | * documentation and/or other materials provided with the distribution. |
16 | * | | 16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 | * SUCH DAMAGE. | | 27 | * SUCH DAMAGE. |
28 | */ | | 28 | */ |
29 | | | 29 | |
30 | #include "efiboot.h" | | 30 | #include "efiboot.h" |
31 | #include "efifdt.h" | | 31 | #include "efifdt.h" |
32 | #include "efiblock.h" | | 32 | #include "efiblock.h" |
33 | | | 33 | |
34 | #include <libfdt.h> | | 34 | #include <libfdt.h> |
35 | | | 35 | |
36 | #define FDT_TABLE_GUID \ | | 36 | #define FDT_TABLE_GUID \ |
37 | { 0xb1b621d5, 0xf19c, 0x41a5, { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } } | | 37 | { 0xb1b621d5, 0xf19c, 0x41a5, { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } } |
38 | static EFI_GUID FdtTableGuid = FDT_TABLE_GUID; | | 38 | static EFI_GUID FdtTableGuid = FDT_TABLE_GUID; |
39 | | | 39 | |
40 | #define FDT_MEMORY_NODE_PATH "/memory" | | 40 | #define FDT_MEMORY_NODE_PATH "/memory" |
41 | #define FDT_MEMORY_NODE_NAME "memory" | | 41 | #define FDT_MEMORY_NODE_NAME "memory" |
42 | #define FDT_CHOSEN_NODE_PATH "/chosen" | | 42 | #define FDT_CHOSEN_NODE_PATH "/chosen" |
43 | #define FDT_CHOSEN_NODE_NAME "chosen" | | 43 | #define FDT_CHOSEN_NODE_NAME "chosen" |
44 | | | 44 | |
45 | #define FDT_MEMORY_USABLE(_md) \ | | 45 | #define FDT_MEMORY_USABLE(_md) \ |
46 | ((_md)->Type == EfiLoaderCode || (_md)->Type == EfiLoaderData || \ | | 46 | ((_md)->Type == EfiLoaderCode || (_md)->Type == EfiLoaderData || \ |
47 | (_md)->Type == EfiBootServicesCode || (_md)->Type == EfiBootServicesData || \ | | 47 | (_md)->Type == EfiBootServicesCode || (_md)->Type == EfiBootServicesData || \ |
48 | (_md)->Type == EfiConventionalMemory) | | 48 | (_md)->Type == EfiConventionalMemory) |
49 | | | 49 | |
50 | static void *fdt_data = NULL; | | 50 | static void *fdt_data = NULL; |
51 | | | 51 | |
52 | int | | 52 | int |
53 | efi_fdt_probe(void) | | 53 | efi_fdt_probe(void) |
54 | { | | 54 | { |
55 | EFI_STATUS status; | | 55 | EFI_STATUS status; |
56 | | | 56 | |
57 | status = LibGetSystemConfigurationTable(&FdtTableGuid, &fdt_data); | | 57 | status = LibGetSystemConfigurationTable(&FdtTableGuid, &fdt_data); |
58 | if (EFI_ERROR(status)) | | 58 | if (EFI_ERROR(status)) |
59 | return EIO; | | 59 | return EIO; |
60 | | | 60 | |
61 | if (fdt_check_header(fdt_data) != 0) { | | 61 | if (fdt_check_header(fdt_data) != 0) { |
62 | fdt_data = NULL; | | 62 | fdt_data = NULL; |
63 | return EINVAL; | | 63 | return EINVAL; |
64 | } | | 64 | } |
65 | | | 65 | |
66 | return 0; | | 66 | return 0; |
67 | } | | 67 | } |
68 | | | 68 | |
69 | int | | 69 | int |
70 | efi_fdt_set_data(void *data) | | 70 | efi_fdt_set_data(void *data) |
71 | { | | 71 | { |
72 | if (fdt_check_header(data) != 0) | | 72 | if (fdt_check_header(data) != 0) |
73 | return EINVAL; | | 73 | return EINVAL; |
74 | | | 74 | |
75 | fdt_data = data; | | 75 | fdt_data = data; |
76 | return 0; | | 76 | return 0; |
77 | } | | 77 | } |
78 | | | 78 | |
79 | void * | | 79 | void * |
80 | efi_fdt_data(void) | | 80 | efi_fdt_data(void) |
81 | { | | 81 | { |
82 | return fdt_data; | | 82 | return fdt_data; |
83 | } | | 83 | } |
84 | | | 84 | |
85 | int | | 85 | int |
86 | efi_fdt_size(void) | | 86 | efi_fdt_size(void) |
87 | { | | 87 | { |
88 | return fdt_data == NULL ? 0 : fdt_totalsize(fdt_data); | | 88 | return fdt_data == NULL ? 0 : fdt_totalsize(fdt_data); |
89 | } | | 89 | } |
90 | | | 90 | |
91 | bool | | 91 | bool |
92 | efi_fdt_overlay_is_compatible(void *dtbo) | | 92 | efi_fdt_overlay_is_compatible(void *dtbo) |
93 | { | | 93 | { |
94 | const int system_root = fdt_path_offset(fdt_data, "/"); | | 94 | const int system_root = fdt_path_offset(fdt_data, "/"); |
95 | const int overlay_root = fdt_path_offset(dtbo, "/"); | | 95 | const int overlay_root = fdt_path_offset(dtbo, "/"); |
96 | | | 96 | |
97 | if (system_root < 0 || overlay_root < 0) | | 97 | if (system_root < 0 || overlay_root < 0) |
98 | return false; | | 98 | return false; |
99 | | | 99 | |
100 | const int system_ncompat = fdt_stringlist_count(fdt_data, system_root, | | 100 | const int system_ncompat = fdt_stringlist_count(fdt_data, system_root, |
101 | "compatible"); | | 101 | "compatible"); |
102 | const int overlay_ncompat = fdt_stringlist_count(dtbo, overlay_root, | | 102 | const int overlay_ncompat = fdt_stringlist_count(dtbo, overlay_root, |
103 | "compatible"); | | 103 | "compatible"); |
104 | | | 104 | |
105 | if (system_ncompat <= 0 || overlay_ncompat <= 0) | | 105 | if (system_ncompat <= 0 || overlay_ncompat <= 0) |
106 | return false; | | 106 | return false; |
107 | | | 107 | |
108 | const char *system_compatible, *overlay_compatible; | | 108 | const char *system_compatible, *overlay_compatible; |
109 | int si, oi; | | 109 | int si, oi; |
110 | | | 110 | |
111 | for (si = 0; si < system_ncompat; si++) { | | 111 | for (si = 0; si < system_ncompat; si++) { |
112 | system_compatible = fdt_stringlist_get(fdt_data, | | 112 | system_compatible = fdt_stringlist_get(fdt_data, |
113 | system_root, "compatible", si, NULL); | | 113 | system_root, "compatible", si, NULL); |
114 | if (system_compatible == NULL) | | 114 | if (system_compatible == NULL) |
115 | continue; | | 115 | continue; |
116 | for (oi = 0; oi < overlay_ncompat; oi++) { | | 116 | for (oi = 0; oi < overlay_ncompat; oi++) { |
117 | overlay_compatible = fdt_stringlist_get(dtbo, | | 117 | overlay_compatible = fdt_stringlist_get(dtbo, |
118 | overlay_root, "compatible", oi, NULL); | | 118 | overlay_root, "compatible", oi, NULL); |
119 | if (overlay_compatible == NULL) | | 119 | if (overlay_compatible == NULL) |
120 | continue; | | 120 | continue; |
121 | if (strcmp(system_compatible, overlay_compatible) == 0) | | 121 | if (strcmp(system_compatible, overlay_compatible) == 0) |
122 | return true; | | 122 | return true; |
123 | } | | 123 | } |
124 | } | | 124 | } |
125 | | | 125 | |
126 | return false; | | 126 | return false; |
127 | } | | 127 | } |
128 | | | 128 | |
129 | int | | 129 | int |
130 | efi_fdt_overlay_apply(void *dtbo, int *fdterr) | | 130 | efi_fdt_overlay_apply(void *dtbo, int *fdterr) |
131 | { | | 131 | { |
132 | int err = fdt_overlay_apply(fdt_data, dtbo); | | 132 | int err = fdt_overlay_apply(fdt_data, dtbo); |
133 | if (fdterr) | | 133 | if (fdterr) |
134 | *fdterr = err; | | 134 | *fdterr = err; |
135 | return err == 0 ? 0 : EIO; | | 135 | return err == 0 ? 0 : EIO; |
136 | } | | 136 | } |
137 | | | 137 | |
138 | void | | 138 | void |
139 | efi_fdt_init(u_long addr, u_long len) | | 139 | efi_fdt_init(u_long addr, u_long len) |
140 | { | | 140 | { |
141 | int error; | | 141 | int error; |
142 | | | 142 | |
143 | error = fdt_open_into(fdt_data, (void *)addr, len); | | 143 | error = fdt_open_into(fdt_data, (void *)addr, len); |
144 | if (error < 0) | | 144 | if (error < 0) |
145 | panic("fdt_open_into failed: %d", error); | | 145 | panic("fdt_open_into failed: %d", error); |
146 | | | 146 | |
147 | fdt_data = (void *)addr; | | 147 | fdt_data = (void *)addr; |
148 | } | | 148 | } |
149 | | | 149 | |
150 | void | | 150 | void |
151 | efi_fdt_fini(void) | | 151 | efi_fdt_fini(void) |
152 | { | | 152 | { |
153 | int error; | | 153 | int error; |
154 | | | 154 | |
155 | error = fdt_pack(fdt_data); | | 155 | error = fdt_pack(fdt_data); |
156 | if (error < 0) | | 156 | if (error < 0) |
157 | panic("fdt_pack failed: %d", error); | | 157 | panic("fdt_pack failed: %d", error); |
158 | } | | 158 | } |
159 | | | 159 | |
160 | void | | 160 | void |
161 | efi_fdt_show(void) | | 161 | efi_fdt_show(void) |
162 | { | | 162 | { |
163 | const char *model, *compat; | | 163 | const char *model, *compat; |
164 | int n, ncompat; | | 164 | int n, ncompat; |
165 | | | 165 | |
166 | if (fdt_data == NULL) | | 166 | if (fdt_data == NULL) |
167 | return; | | 167 | return; |
168 | | | 168 | |
169 | model = fdt_getprop(fdt_data, fdt_path_offset(fdt_data, "/"), "model", NULL); | | 169 | model = fdt_getprop(fdt_data, fdt_path_offset(fdt_data, "/"), "model", NULL); |
170 | if (model) | | 170 | if (model) |
171 | printf("FDT: %s [", model); | | 171 | printf("FDT: %s [", model); |
172 | ncompat = fdt_stringlist_count(fdt_data, fdt_path_offset(fdt_data, "/"), "compatible"); | | 172 | ncompat = fdt_stringlist_count(fdt_data, fdt_path_offset(fdt_data, "/"), "compatible"); |
173 | for (n = 0; n < ncompat; n++) { | | 173 | for (n = 0; n < ncompat; n++) { |
174 | compat = fdt_stringlist_get(fdt_data, fdt_path_offset(fdt_data, "/"), | | 174 | compat = fdt_stringlist_get(fdt_data, fdt_path_offset(fdt_data, "/"), |
175 | "compatible", n, NULL); | | 175 | "compatible", n, NULL); |
176 | printf("%s%s", n == 0 ? "" : ", ", compat); | | 176 | printf("%s%s", n == 0 ? "" : ", ", compat); |
177 | } | | 177 | } |
178 | printf("]\n"); | | 178 | printf("]\n"); |
179 | } | | 179 | } |
180 | | | 180 | |
181 | void | | 181 | void |
182 | efi_fdt_memory_map(void) | | 182 | efi_fdt_memory_map(void) |
183 | { | | 183 | { |
184 | UINTN nentries = 0, mapkey, descsize; | | 184 | UINTN nentries = 0, mapkey, descsize; |
185 | EFI_MEMORY_DESCRIPTOR *md, *memmap; | | 185 | EFI_MEMORY_DESCRIPTOR *md, *memmap; |
186 | UINT32 descver; | | 186 | UINT32 descver; |
187 | UINT64 phys_start, phys_size; | | 187 | UINT64 phys_start, phys_size; |
188 | int n, memory, chosen; | | 188 | int n, memory, chosen; |
189 | | | 189 | |
190 | memory = fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH); | | 190 | memory = fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH); |
191 | if (memory < 0) | | 191 | if (memory < 0) |
192 | memory = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_MEMORY_NODE_NAME); | | 192 | memory = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_MEMORY_NODE_NAME); |
193 | if (memory < 0) | | 193 | if (memory < 0) |
194 | panic("FDT: Failed to create " FDT_MEMORY_NODE_PATH " node"); | | 194 | panic("FDT: Failed to create " FDT_MEMORY_NODE_PATH " node"); |
195 | | | 195 | |
196 | chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); | | 196 | chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); |
197 | if (chosen < 0) | | 197 | if (chosen < 0) |
198 | chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); | | 198 | chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); |
199 | if (chosen < 0) | | 199 | if (chosen < 0) |
200 | panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); | | 200 | panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); |
201 | | | 201 | |
202 | fdt_delprop(fdt_data, memory, "reg"); | | 202 | fdt_delprop(fdt_data, memory, "reg"); |
203 | | | 203 | |
204 | const int address_cells = fdt_address_cells(fdt_data, fdt_path_offset(fdt_data, "/")); | | 204 | const int address_cells = fdt_address_cells(fdt_data, fdt_path_offset(fdt_data, "/")); |
205 | const int size_cells = fdt_size_cells(fdt_data, fdt_path_offset(fdt_data, "/")); | | 205 | const int size_cells = fdt_size_cells(fdt_data, fdt_path_offset(fdt_data, "/")); |
206 | | | 206 | |
207 | memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver); | | 207 | memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver); |
208 | for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) { | | 208 | for (n = 0, md = memmap; n < nentries; n++, md = NextMemoryDescriptor(md, descsize)) { |
209 | fdt_appendprop_u32(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->Type); | | 209 | fdt_appendprop_u32(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->Type); |
210 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->PhysicalStart); | | 210 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->PhysicalStart); |
211 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->NumberOfPages); | | 211 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->NumberOfPages); |
212 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->Attribute); | | 212 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "netbsd,uefi-memmap", md->Attribute); |
213 | | | 213 | |
214 | if ((md->Attribute & EFI_MEMORY_RUNTIME) != 0) | | 214 | if ((md->Attribute & EFI_MEMORY_RUNTIME) != 0) |
215 | continue; | | 215 | continue; |
216 | | | 216 | |
217 | if ((md->Attribute & EFI_MEMORY_WB) == 0) | | 217 | if ((md->Attribute & EFI_MEMORY_WB) == 0) |
218 | continue; | | 218 | continue; |
219 | if (!FDT_MEMORY_USABLE(md)) | | 219 | if (!FDT_MEMORY_USABLE(md)) |
220 | continue; | | 220 | continue; |
221 | if ((address_cells == 1 || size_cells == 1) && md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) > 0xffffffff) | | 221 | if ((address_cells == 1 || size_cells == 1) && md->PhysicalStart + (md->NumberOfPages * EFI_PAGE_SIZE) > 0xffffffff) |
222 | continue; | | 222 | continue; |
223 | if (md->NumberOfPages <= 1) | | 223 | if (md->NumberOfPages <= 1) |
224 | continue; | | 224 | continue; |
225 | | | 225 | |
226 | phys_start = md->PhysicalStart; | | 226 | phys_start = md->PhysicalStart; |
227 | phys_size = md->NumberOfPages * EFI_PAGE_SIZE; | | 227 | phys_size = md->NumberOfPages * EFI_PAGE_SIZE; |
228 | | | 228 | |
229 | if (phys_start & EFI_PAGE_MASK) { | | 229 | if (phys_start & EFI_PAGE_MASK) { |
230 | /* UEFI spec says these should be 4KB aligned, but U-Boot doesn't always.. */ | | 230 | /* UEFI spec says these should be 4KB aligned, but U-Boot doesn't always.. */ |
231 | phys_start = (phys_start + EFI_PAGE_SIZE) & ~EFI_PAGE_MASK; | | 231 | phys_start = (phys_start + EFI_PAGE_SIZE) & ~EFI_PAGE_MASK; |
232 | phys_size -= (EFI_PAGE_SIZE * 2); | | 232 | phys_size -= (EFI_PAGE_SIZE * 2); |
233 | if (phys_size == 0) | | 233 | if (phys_size == 0) |
234 | continue; | | 234 | continue; |
235 | } | | 235 | } |
236 | | | 236 | |
237 | if (address_cells == 1) | | 237 | if (address_cells == 1) |
238 | fdt_appendprop_u32(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), | | 238 | fdt_appendprop_u32(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), |
239 | "reg", (uint32_t)phys_start); | | 239 | "reg", (uint32_t)phys_start); |
240 | else | | 240 | else |
241 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), | | 241 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), |
242 | "reg", phys_start); | | 242 | "reg", phys_start); |
243 | | | 243 | |
244 | if (size_cells == 1) | | 244 | if (size_cells == 1) |
245 | fdt_appendprop_u32(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), | | 245 | fdt_appendprop_u32(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), |
246 | "reg", (uint32_t)phys_size); | | 246 | "reg", (uint32_t)phys_size); |
247 | else | | 247 | else |
248 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), | | 248 | fdt_appendprop_u64(fdt_data, fdt_path_offset(fdt_data, FDT_MEMORY_NODE_PATH), |
249 | "reg", phys_size); | | 249 | "reg", phys_size); |
250 | } | | 250 | } |
251 | } | | 251 | } |
252 | | | 252 | |
253 | void | | 253 | void |
254 | efi_fdt_gop(void) | | 254 | efi_fdt_gop(void) |
255 | { | | 255 | { |
256 | EFI_STATUS status; | | 256 | EFI_STATUS status; |
257 | EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; | | 257 | EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; |
258 | EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode; | | 258 | EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode; |
259 | EFI_HANDLE *gop_handle; | | 259 | EFI_HANDLE *gop_handle; |
260 | UINTN ngop_handle, n; | | 260 | UINTN ngop_handle, n; |
261 | char buf[48]; | | 261 | char buf[48]; |
262 | int fb; | | 262 | int fb; |
263 | | | 263 | |
264 | status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol, NULL, &ngop_handle, &gop_handle); | | 264 | status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol, NULL, &ngop_handle, &gop_handle); |
265 | if (EFI_ERROR(status) || ngop_handle == 0) | | 265 | if (EFI_ERROR(status) || ngop_handle == 0) |
266 | return; | | 266 | return; |
267 | | | 267 | |
268 | for (n = 0; n < ngop_handle; n++) { | | 268 | for (n = 0; n < ngop_handle; n++) { |
269 | status = uefi_call_wrapper(BS->HandleProtocol, 3, gop_handle[n], &GraphicsOutputProtocol, (void **)&gop); | | 269 | status = uefi_call_wrapper(BS->HandleProtocol, 3, gop_handle[n], &GraphicsOutputProtocol, (void **)&gop); |
270 | if (EFI_ERROR(status)) | | 270 | if (EFI_ERROR(status)) |
271 | continue; | | 271 | continue; |
272 | | | 272 | |
273 | mode = gop->Mode; | | 273 | mode = gop->Mode; |
274 | if (mode == NULL) | | 274 | if (mode == NULL) |
275 | continue; | | 275 | continue; |
276 | | | 276 | |
277 | #ifdef EFIBOOT_DEBUG | | 277 | #ifdef EFIBOOT_DEBUG |
278 | printf("GOP: FB @ 0x%lx size 0x%lx\n", mode->FrameBufferBase, mode->FrameBufferSize); | | 278 | printf("GOP: FB @ 0x%lx size 0x%lx\n", mode->FrameBufferBase, mode->FrameBufferSize); |
279 | printf("GOP: Version %d\n", mode->Info->Version); | | 279 | printf("GOP: Version %d\n", mode->Info->Version); |
280 | printf("GOP: HRes %d VRes %d\n", mode->Info->HorizontalResolution, mode->Info->VerticalResolution); | | 280 | printf("GOP: HRes %d VRes %d\n", mode->Info->HorizontalResolution, mode->Info->VerticalResolution); |
281 | printf("GOP: PixelFormat %d\n", mode->Info->PixelFormat); | | 281 | printf("GOP: PixelFormat %d\n", mode->Info->PixelFormat); |
282 | printf("GOP: PixelBitmask R 0x%x G 0x%x B 0x%x Res 0x%x\n", | | 282 | printf("GOP: PixelBitmask R 0x%x G 0x%x B 0x%x Res 0x%x\n", |
283 | mode->Info->PixelInformation.RedMask, | | 283 | mode->Info->PixelInformation.RedMask, |
284 | mode->Info->PixelInformation.GreenMask, | | 284 | mode->Info->PixelInformation.GreenMask, |
285 | mode->Info->PixelInformation.BlueMask, | | 285 | mode->Info->PixelInformation.BlueMask, |
286 | mode->Info->PixelInformation.ReservedMask); | | 286 | mode->Info->PixelInformation.ReservedMask); |
287 | printf("GOP: Pixels per scanline %d\n", mode->Info->PixelsPerScanLine); | | 287 | printf("GOP: Pixels per scanline %d\n", mode->Info->PixelsPerScanLine); |
288 | #endif | | 288 | #endif |
289 | | | 289 | |
290 | if (mode->Info->PixelFormat == PixelBltOnly) { | | 290 | if (mode->Info->PixelFormat == PixelBltOnly) { |
291 | printf("GOP: PixelBltOnly pixel format not supported\n"); | | 291 | printf("GOP: PixelBltOnly pixel format not supported\n"); |
292 | continue; | | 292 | continue; |
293 | } | | 293 | } |
294 | | | 294 | |
| | | 295 | fdt_setprop_u32(fdt_data, |
| | | 296 | fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "#address-cells", 2); |
| | | 297 | fdt_setprop_u32(fdt_data, |
| | | 298 | fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "#size-cells", 2); |
| | | 299 | fdt_setprop_empty(fdt_data, |
| | | 300 | fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), "ranges"); |
| | | 301 | |
295 | snprintf(buf, sizeof(buf), "framebuffer@%" PRIx64, mode->FrameBufferBase); | | 302 | snprintf(buf, sizeof(buf), "framebuffer@%" PRIx64, mode->FrameBufferBase); |
296 | fb = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/chosen"), buf); | | 303 | fb = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), buf); |
297 | if (fb < 0) | | 304 | if (fb < 0) |
298 | panic("FDT: Failed to create framebuffer node"); | | 305 | panic("FDT: Failed to create framebuffer node"); |
299 | | | 306 | |
300 | fdt_appendprop_string(fdt_data, fb, "compatible", "simple-framebuffer"); | | 307 | fdt_appendprop_string(fdt_data, fb, "compatible", "simple-framebuffer"); |
301 | fdt_appendprop_string(fdt_data, fb, "status", "okay"); | | 308 | fdt_appendprop_string(fdt_data, fb, "status", "okay"); |
302 | fdt_appendprop_u64(fdt_data, fb, "reg", mode->FrameBufferBase); | | 309 | fdt_appendprop_u64(fdt_data, fb, "reg", mode->FrameBufferBase); |
303 | fdt_appendprop_u64(fdt_data, fb, "reg", mode->FrameBufferSize); | | 310 | fdt_appendprop_u64(fdt_data, fb, "reg", mode->FrameBufferSize); |
304 | fdt_appendprop_u32(fdt_data, fb, "width", mode->Info->HorizontalResolution); | | 311 | fdt_appendprop_u32(fdt_data, fb, "width", mode->Info->HorizontalResolution); |
305 | fdt_appendprop_u32(fdt_data, fb, "height", mode->Info->VerticalResolution); | | 312 | fdt_appendprop_u32(fdt_data, fb, "height", mode->Info->VerticalResolution); |
306 | fdt_appendprop_u32(fdt_data, fb, "stride", mode->Info->PixelsPerScanLine * 4); /* XXX */ | | 313 | fdt_appendprop_u32(fdt_data, fb, "stride", mode->Info->PixelsPerScanLine * 4); /* XXX */ |
307 | fdt_appendprop_string(fdt_data, fb, "format", "a8b8g8r8"); | | 314 | fdt_appendprop_string(fdt_data, fb, "format", "a8b8g8r8"); |
308 | | | 315 | |
309 | snprintf(buf, sizeof(buf), "/chosen/framebuffer@%" PRIx64, mode->FrameBufferBase); | | 316 | snprintf(buf, sizeof(buf), "/chosen/framebuffer@%" PRIx64, mode->FrameBufferBase); |
310 | fdt_setprop_string(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), | | 317 | fdt_setprop_string(fdt_data, fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH), |
311 | "stdout-path", buf); | | 318 | "stdout-path", buf); |
312 | | | 319 | |
313 | return; | | 320 | return; |
314 | } | | 321 | } |
315 | } | | 322 | } |
316 | | | 323 | |
317 | void | | 324 | void |
318 | efi_fdt_bootargs(const char *bootargs) | | 325 | efi_fdt_bootargs(const char *bootargs) |
319 | { | | 326 | { |
320 | struct efi_block_part *bpart = efi_block_boot_part(); | | 327 | struct efi_block_part *bpart = efi_block_boot_part(); |
321 | uint8_t macaddr[6]; | | 328 | uint8_t macaddr[6]; |
322 | int chosen; | | 329 | int chosen; |
323 | | | 330 | |
324 | chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); | | 331 | chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); |
325 | if (chosen < 0) | | 332 | if (chosen < 0) |
326 | chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); | | 333 | chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); |
327 | if (chosen < 0) | | 334 | if (chosen < 0) |
328 | panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); | | 335 | panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); |
329 | | | 336 | |
330 | fdt_setprop_u32(fdt_data, chosen, "#address-cells", 2); | | | |
331 | fdt_setprop_u32(fdt_data, chosen, "#size-cells", 2); | | | |
332 | fdt_setprop_empty(fdt_data, chosen, "ranges"); | | | |
333 | | | | |
334 | if (*bootargs) | | 337 | if (*bootargs) |
335 | fdt_setprop_string(fdt_data, chosen, "bootargs", bootargs); | | 338 | fdt_setprop_string(fdt_data, chosen, "bootargs", bootargs); |
336 | | | 339 | |
337 | if (bpart) { | | 340 | if (bpart) { |
338 | switch (bpart->type) { | | 341 | switch (bpart->type) { |
339 | case EFI_BLOCK_PART_DISKLABEL: | | 342 | case EFI_BLOCK_PART_DISKLABEL: |
340 | fdt_setprop(fdt_data, chosen, "netbsd,mbr", | | 343 | fdt_setprop(fdt_data, chosen, "netbsd,mbr", |
341 | bpart->hash, sizeof(bpart->hash)); | | 344 | bpart->hash, sizeof(bpart->hash)); |
342 | fdt_setprop_u32(fdt_data, chosen, "netbsd,partition", | | 345 | fdt_setprop_u32(fdt_data, chosen, "netbsd,partition", |
343 | bpart->index); | | 346 | bpart->index); |
344 | break; | | 347 | break; |
345 | case EFI_BLOCK_PART_GPT: | | 348 | case EFI_BLOCK_PART_GPT: |
346 | if (bpart->gpt.ent.ent_name[0] == 0x0000) { | | 349 | if (bpart->gpt.ent.ent_name[0] == 0x0000) { |
347 | fdt_setprop(fdt_data, chosen, "netbsd,gpt-guid", | | 350 | fdt_setprop(fdt_data, chosen, "netbsd,gpt-guid", |
348 | bpart->hash, sizeof(bpart->hash)); | | 351 | bpart->hash, sizeof(bpart->hash)); |
349 | } else { | | 352 | } else { |
350 | char *label = NULL; | | 353 | char *label = NULL; |
351 | int rv = ucs2_to_utf8(bpart->gpt.ent.ent_name, &label); | | 354 | int rv = ucs2_to_utf8(bpart->gpt.ent.ent_name, &label); |
352 | if (rv == 0) { | | 355 | if (rv == 0) { |
353 | fdt_setprop_string(fdt_data, chosen, "netbsd,gpt-label", label); | | 356 | fdt_setprop_string(fdt_data, chosen, "netbsd,gpt-label", label); |
354 | FreePool(label); | | 357 | FreePool(label); |
355 | } | | 358 | } |
356 | } | | 359 | } |
357 | break; | | 360 | break; |
358 | default: | | 361 | default: |
359 | break; | | 362 | break; |
360 | } | | 363 | } |
361 | } else if (efi_net_get_booted_macaddr(macaddr) == 0) { | | 364 | } else if (efi_net_get_booted_macaddr(macaddr) == 0) { |
362 | fdt_setprop(fdt_data, chosen, "netbsd,booted-mac-address", macaddr, sizeof(macaddr)); | | 365 | fdt_setprop(fdt_data, chosen, "netbsd,booted-mac-address", macaddr, sizeof(macaddr)); |
363 | } | | 366 | } |
364 | } | | 367 | } |
365 | | | 368 | |
366 | void | | 369 | void |
367 | efi_fdt_initrd(u_long initrd_addr, u_long initrd_size) | | 370 | efi_fdt_initrd(u_long initrd_addr, u_long initrd_size) |
368 | { | | 371 | { |
369 | int chosen; | | 372 | int chosen; |
370 | | | 373 | |
371 | if (initrd_size == 0) | | 374 | if (initrd_size == 0) |
372 | return; | | 375 | return; |
373 | | | 376 | |
374 | chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); | | 377 | chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); |
375 | if (chosen < 0) | | 378 | if (chosen < 0) |
376 | chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); | | 379 | chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); |
377 | if (chosen < 0) | | 380 | if (chosen < 0) |
378 | panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); | | 381 | panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); |
379 | | | 382 | |
380 | fdt_setprop_u64(fdt_data, chosen, "linux,initrd-start", initrd_addr); | | 383 | fdt_setprop_u64(fdt_data, chosen, "linux,initrd-start", initrd_addr); |
381 | fdt_setprop_u64(fdt_data, chosen, "linux,initrd-end", initrd_addr + initrd_size); | | 384 | fdt_setprop_u64(fdt_data, chosen, "linux,initrd-end", initrd_addr + initrd_size); |
382 | } | | 385 | } |