]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S
ArmVirtualizationPkg: Xen/PV relocatable platformlib instance
[mirror_edk2.git] / ArmPlatformPkg / ArmVirtualizationPkg / Library / ArmXenRelocatablePlatformLib / AARCH64 / MemnodeParser.S
1 /*
2 * Copyright (c) 2014, Linaro Ltd. All rights reserved.
3 *
4 * This program and the accompanying materials
5 * are licensed and made available under the terms and conditions of the BSD License
6 * which accompanies this distribution. The full text of the license may be found at
7 * http://opensource.org/licenses/bsd-license.php
8 *
9 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 */
12
13 /*
14 * Theory of operation
15 * -------------------
16 *
17 * This code parses a Flattened Device Tree binary (DTB) to find the base of
18 * system RAM. It is written in assembly so that it can be executed before a
19 * stack has been set up.
20 *
21 * To find the base of system RAM, we have to traverse the FDT to find a memory
22 * node. In the context of this implementation, the first node that has a
23 * device_type property with the value 'memory' and a 'reg' property is
24 * acceptable, and the name of the node (memory[@xxx]) is ignored, as are any
25 * other nodes that match the above constraints.
26 *
27 * In pseudo code, this implementation does the following:
28 *
29 * for each node {
30 * have_device_type = false
31 * have_reg = false
32 *
33 * for each property {
34 * if property value == 'memory' {
35 * if property name == 'device_type' {
36 * have_device_type = true
37 * }
38 * } else {
39 * if property name == 'reg' {
40 * have_reg = true
41 * membase = property value[0]
42 * memsize = property value[1]
43 * }
44 * }
45 * }
46 * if have_device_type and have_reg {
47 * return membase and memsize
48 * }
49 * }
50 * return NOT_FOUND
51 */
52
53 #define FDT_MAGIC 0xedfe0dd0
54
55 #define FDT_BEGIN_NODE 0x1
56 #define FDT_END_NODE 0x2
57 #define FDT_PROP 0x3
58 #define FDT_END 0x9
59
60 xMEMSIZE .req x0 // recorded system RAM size
61 xMEMBASE .req x1 // recorded system RAM base
62
63 xLR .req x8 // our preserved link register
64 xDTP .req x9 // pointer to traverse the DT structure
65 xSTRTAB .req x10 // pointer to the DTB string table
66 xMEMNODE .req x11 // bit field to record found properties
67
68 #define HAVE_REG 0x1
69 #define HAVE_DEVICE_TYPE 0x2
70
71 .text
72 .align 3
73 _memory:
74 .asciz "memory"
75 _reg:
76 .asciz "reg"
77 _device_type:
78 .asciz "device_type"
79
80 /*
81 * Compare strings in x4 and x5, return in w7
82 */
83 .align 3
84 strcmp:
85 ldrb w2, [x4], #1
86 ldrb w3, [x5], #1
87 subs w7, w2, w3
88 cbz w2, 0f
89 cbz w3, 0f
90 beq strcmp
91 0: ret
92
93 .globl find_memnode
94 find_memnode:
95 // preserve link register
96 mov xLR, x30
97 mov xDTP, x0
98
99 /*
100 * Check the DTB magic at offset 0
101 */
102 movz w4, #:abs_g0_nc:FDT_MAGIC
103 movk w4, #:abs_g1:FDT_MAGIC
104 ldr w5, [xDTP]
105 cmp w4, w5
106 bne err_invalid_magic
107
108 /*
109 * Read the string offset and store it for later use
110 */
111 ldr w4, [xDTP, #12]
112 rev w4, w4
113 add xSTRTAB, xDTP, x4
114
115 /*
116 * Read the struct offset and add it to the DT pointer
117 */
118 ldr w5, [xDTP, #8]
119 rev w5, w5
120 add xDTP, xDTP, x5
121
122 /*
123 * Check current tag for FDT_BEGIN_NODE
124 */
125 ldr w5, [xDTP]
126 rev w5, w5
127 cmp w5, #FDT_BEGIN_NODE
128 bne err_unexpected_begin_tag
129
130 begin_node:
131 mov xMEMNODE, #0
132 add xDTP, xDTP, #4
133
134 /*
135 * Advance xDTP past NULL terminated string
136 */
137 0: ldrb w4, [xDTP], #1
138 cbnz w4, 0b
139
140 next_tag:
141 /*
142 * Align the DT pointer xDTP to the next 32-bit boundary
143 */
144 add xDTP, xDTP, #3
145 and xDTP, xDTP, #~3
146
147 /*
148 * Read the next tag, could be BEGIN_NODE, END_NODE, PROP, END
149 */
150 ldr w5, [xDTP]
151 rev w5, w5
152 cmp w5, #FDT_BEGIN_NODE
153 beq begin_node
154 cmp w5, #FDT_END_NODE
155 beq end_node
156 cmp w5, #FDT_PROP
157 beq prop_node
158 cmp w5, #FDT_END
159 beq err_end_of_fdt
160 b err_unexpected_tag
161
162 prop_node:
163 /*
164 * If propname == 'reg', record as membase and memsize
165 * If propname == 'device_type' and value == 'memory',
166 * set the 'is_memnode' flag for this node
167 */
168 ldr w6, [xDTP, #4]
169 add xDTP, xDTP, #12
170 rev w6, w6
171 mov x5, xDTP
172 adr x4, _memory
173 bl strcmp
174
175 /*
176 * Get handle to property name
177 */
178 ldr w5, [xDTP, #-4]
179 rev w5, w5
180 add x5, xSTRTAB, x5
181
182 cbz w7, check_device_type
183
184 /*
185 * Check for 'reg' property
186 */
187 adr x4, _reg
188 bl strcmp
189 cbnz w7, inc_and_next_tag
190
191 /*
192 * Extract two 64-bit quantities from the 'reg' property. These values
193 * will only be used if the node also turns out to have a device_type
194 * property with a value of 'memory'.
195 *
196 * NOTE: xDTP is only guaranteed to be 32 bit aligned, and we are most
197 * likely executing with the MMU off, so we cannot use 64 bit
198 * wide accesses here.
199 */
200 ldp w4, w5, [xDTP]
201 orr xMEMBASE, x4, x5, lsl #32
202 ldp w4, w5, [xDTP, #8]
203 orr xMEMSIZE, x4, x5, lsl #32
204 rev xMEMBASE, xMEMBASE
205 rev xMEMSIZE, xMEMSIZE
206 orr xMEMNODE, xMEMNODE, #HAVE_REG
207 b inc_and_next_tag
208
209 check_device_type:
210 /*
211 * Check whether the current property's name is 'device_type'
212 */
213 adr x4, _device_type
214 bl strcmp
215 cbnz w7, inc_and_next_tag
216 orr xMEMNODE, xMEMNODE, #HAVE_DEVICE_TYPE
217
218 inc_and_next_tag:
219 add xDTP, xDTP, x6
220 b next_tag
221
222 end_node:
223 /*
224 * Check for device_type = memory and reg = xxxx
225 * If we have both, we are done
226 */
227 add xDTP, xDTP, #4
228 cmp xMEMNODE, #(HAVE_REG | HAVE_DEVICE_TYPE)
229 bne next_tag
230
231 ret xLR
232
233 err_invalid_magic:
234 err_unexpected_begin_tag:
235 err_unexpected_tag:
236 err_end_of_fdt:
237 wfi