summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/llfw/nvramlog.S
blob: 3ad2de75440812a32682c6f8e1ecabe1ce771736 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation
 * All rights reserved.
 * This program and the accompanying materials
 * are made available under the terms of the BSD License
 * which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/bsd-license.php
 *
 * Contributors:
 *     IBM Corporation - initial implementation
 *****************************************************************************/
#include <macros.h>
#include <nvramlog.h>
#include <southbridge.h>
#include <calculatecrc.h>

#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM)

// detect overflow: if(a<b)  return a else return 0
#define NVRAM_LOG_DATA_OVERFLOW( a, b) \
	cmpd    7, a, b; \
	blt+    7, 0f; \
	li      a, 0; \
	0:

// get Pointer(pointer) to next byte in NVRAM data section
//  and size of this data sechtion (modulo)
// modifies register pointer, modulo
#define NVRAM_POINTER_DATASIZE_BE0(pointer, modulo, address) \
	LOAD64(	modulo, LLFW_LOG_BE0_LENGTH); \
	lwz     pointer, LLFW_LOG_POS_POINTER(address); \
	sldi    modulo, modulo, 4; \
	addi    modulo, modulo,-LLFW_LOG_BE0_DATA_OFFSET
#define NVRAM_POINTER_DATASIZE_BE1(pointer, modulo, address) \
	LOAD64(	modulo, LLFW_LOG_BE1_LENGTH); \
	lwz     pointer, LLFW_LOG_POS_POINTER(address); \
	sldi    modulo, modulo, 4; \
	addi    modulo, modulo,-LLFW_LOG_BE1_DATA_OFFSET

/****************************************************************************
 *	checkLogHeaderData
 *	compare the fixed values in the header if any change was done since
 *	last initialisation.
 *	Flags are not checked!
 *
 *	Retrun 0 if no manimulation was found 1 else
 *
 *	input:
 *			r3 - NVRAM Base Address 
 *
 *	output:
 *			r3 - status: 0 = ok, 1 = corrupt
 *			r4 - NVRAM Base Address
 *
 ***************************************************************************/
ASM_ENTRY(checkLogHeaderData)
	li	r4, 0					// init error flag
	lbz	r5, 0(r3)				// check signature
	addi	r5, r5, -LLFW_LOG_BE0_SIGNATURE
	add	r4, r4, r5

	lhz	r5, LLFW_LOG_POS_LENGTH(r3)		// check length
	addi	r5, r5, -LLFW_LOG_BE0_LENGTH
	add 	r4, r4, r5

	lwz	r5, LLFW_LOG_POS_NAME(r3)		// check name prefix
	LOAD64( r6, LLFW_LOG_BE0_NAME_PREFIX)
	subf	r5, r6, r5
	add	r4, r4, r5

	ld	r5, (LLFW_LOG_POS_NAME+4)(r3)		// check name
	LOAD64(	r6, LLFW_LOG_BE0_NAME)
	subf	r5, r6, r5
	add	r4, r4, r5
	
	lhz	r5, LLFW_LOG_POS_DATA_OFFSET(r3)	//check data offset
	addi	r5, r5, -LLFW_LOG_BE0_DATA_OFFSET
	add	r4, r4, r5

	lhz	r5, LLFW_LOG_POS_FLAGS(r3)		//check flags
	addi	r5, r5, -LLFW_LOG_BE0_FLAGS
	add	r4, r4, r5

	cmpldi	7, r4, 0
	beq+	7, 0f
	li	r4, 1
0:
	mr	r5, r3
	mr	r3, r4
	mr	r4, r5
	blr
/*****************************************************************************
 * checkLogPartition:	check Partition Header entries and Checksum
 *			check also the NVRAM-Log-Partition CRC
 *			if Partition is not ok set the following bits to 1
 *			bit 1:	if Partiton Header Checksum is corrupt
 *			bit 2: 	if CRC is corrupt
 *			bit 3: 	if Header entries are corrupt
 *						
 *	input:	
 *		r3 - NVRAM log address (BASE + NVRAM_LOG_OFFSET)
 *
 *	output:	
 *		r3 - CRC status  
 *		r4 - NVRAM log address
 *
 *	Modifies Register:	R3, R4, R5, R6, R7, R8, R9
 ****************************************************************************/
ASM_ENTRY(.checkLogPartition)
	mflr	r8
	mr      r4, r3                  // emulate "bl updateCRC_NVRAM"
	li      r3, 0                   // with successful CRC check
	li      r7, 0
	cmpwi   7, r3, 0
	beq+    7, 0f
	li      r7, 2
0:
	mr	r3, r4
	bl 	.calPartitionHeaderChecksum	// r3=checksum, r4=NVARM addr
	lbz	r6, LLFW_LOG_POS_CHECKSUM(r4)
	cmpw	7, r3, r6
	beq+	7, 0f			// cal checksum must eq checksum
	ori	r7, r7, 1
0:
	cmpwi	7, r3, 0
	bne+	7, 0f
	ori	r7, r7, 1		// 0 as checksum is invalid
0:
	mr	r3, r4
	bl	checkLogHeaderData	
	cmpdi	7, r3, 0
	beq+	7, 0f
	ori	r7, r7, 4
0:
	mr	r3, r7
	mtlr	r8
	blr
/*****************************************************************************
 * checkinitLog:	check the NVRAM Log Partition Header 
 *			initialize the NVRAM if the Header was modified
 *					
 *	input:	
 *		r3 - NVRAM BASE address 
 *
 *	output:	
 *		r3 - 0 = check ok, no new header written
 *		r3 - 1 = check not ok, header and NVRAM initialized
 *		r4 - NVRAM log address
 *
 *	Modifies Register:	R3, R4, R5, R6, R7, r8, r9
 ****************************************************************************/
// init is done if checkLogPartiton returns not 0 (= check failed)
ASM_ENTRY(.checkinitLog)
ASM_ENTRY(checkinitLog)
	mflr	r9
	bl 	.checkLogPartition		//r3..r8, r4_out = r3_in   
	mtlr	r9
	
	cmpwi	7, r3, 0
	mr	r3, r4			// r3=NVRAM_LOG address
	bne-	7, .initLog		// if header is not ok, init header
	li	r3, 0
	blr				// header OK, return 0			


/* this is basically just a copy of .initLog 
   registers used: r3, r4, r5, r6, r7, r9*/
init_log_2nd_be:
	mflr	r9	
	li	r6, LLFW_LOG_BE0_LENGTH
	mulli	r6, r6, 0x10
	add	r6, r7, r6
	li      r5, LLFW_LOG_BE1_SIGNATURE
	li      r4, LLFW_LOG_BE1_LENGTH
	stb     r5, 0(r6)
	sth     r4, LLFW_LOG_POS_LENGTH(r6)
	li      r5, LLFW_LOG_BE1_DATA_OFFSET
	li      r4, LLFW_LOG_BE1_FLAGS
	sth     r5, LLFW_LOG_POS_DATA_OFFSET(r6)
	sth     r4, LLFW_LOG_POS_FLAGS(r6)
	li      r5, 1

	LOAD32( r4, LLFW_LOG_BE1_NAME_PREFIX)
	stw     r5, LLFW_LOG_POS_POINTER(r6)
	stw     r4, (LLFW_LOG_POS_NAME+0x00)(r6)
	LOAD64( r5, LLFW_LOG_BE1_NAME)
	std     r5, (LLFW_LOG_POS_NAME+0x04)(r6)
	mr	r3, r6
	bl 	.calPartitionHeaderChecksum
	stb     r3, LLFW_LOG_POS_CHECKSUM(r6)
	mtlr	r9
	blr
/*****************************************************************************
 * initLog:	initialize the NVRAM with 0
 *		write a new NVRAM Log-Partition-Header
 *					
 *	input:	
 *		r3 - NVRAM BASE address 
 *
 *	output:	
 *		r3 - 0 = check ok, no new header written
 *		r3 - 1 = check not ok, header and NVRAM initialized
 *		r4 - NVRAM log address
 *
 *	Modifies Register:	R3, R4, R5, R6, R7, r8, r9
 ****************************************************************************/
ASM_ENTRY(.initLog)
 	mflr    r8
	mr	r7, r3

	bl clearNVRAM
0:
	li      r5, LLFW_LOG_BE0_SIGNATURE
	li      r4, LLFW_LOG_BE0_LENGTH
	stb     r5, 0(r7)
	sth     r4, LLFW_LOG_POS_LENGTH(r7)
	li      r5, LLFW_LOG_BE0_DATA_OFFSET
	li      r4, LLFW_LOG_BE0_FLAGS
	sth     r5, LLFW_LOG_POS_DATA_OFFSET(r7)
	sth     r4, LLFW_LOG_POS_FLAGS(r7)
	li      r5, 1

	LOAD32( r4, LLFW_LOG_BE0_NAME_PREFIX)
	stw     r5, LLFW_LOG_POS_POINTER(r7)
	stw     r4, (LLFW_LOG_POS_NAME+0x00)(r7)
	LOAD64( r5, LLFW_LOG_BE0_NAME)
	std     r5, (LLFW_LOG_POS_NAME+0x04)(r7)
	bl 	.calPartitionHeaderChecksum
	stb     r3, LLFW_LOG_POS_CHECKSUM(r7)
	bl	init_log_2nd_be			// create a second log partition for BE1
	mr	r4, r7
	li	r3, 1
	mtlr 	r8
	blr
/*****************************************************************************
 *	clearNVRAM:	set all not used NVRAM memory to zero
 *
 *
 *	input:	
 *		R3 - NVRAM BASE ADDRESS
 *
 *	output:	
 *		R3 - NVARM END ADDRESS
 *
 *	Modifies Register: r4, r5
 ****************************************************************************/
ASM_ENTRY(clearNVRAM)
	LOAD64(	r4, NVRAM_LENGTH)
	srdi	r4, r4, 3
	mtctr	r4
	li	r5, 0x0
	LOAD64(	r4, NVRAM_EMPTY_PATTERN)
0:
	stdx	r4, r3,r5
	addi	r5, r5, 8
	bdnz+	0b
	blr	
/*****************************************************************************
 * writeNVRAMbyte:	write next log into NVRAM
 *					
 *
 *	input:	
 *		R3 - byte to be written
 *		R4 - NVRAM Base Address
 *
 *	output:	
 *		R3 - byte that was written
 *		R4 - NVRAM Base Address 
 *
 * 	Modifies Register:	R3, R4, R5, R6
 ****************************************************************************/
ASM_ENTRY(.writeNVRAMbyte)
ENTRY(writeLogByte)
	NVRAM_POINTER_DATASIZE_BE0( r5, r6, r4)	// get pointer,size of data
	NVRAM_LOG_DATA_OVERFLOW( r5, r6)	// check for overflow
	addi    r5, r5, 1                       // increment pointer
	stw     r5, LLFW_LOG_POS_POINTER(r4)    // store pointer
	addi    r5, r5, -1			// restore old pointer
	add     r6, r4, r5                      // byte address in data section 

	stb 	r3, LLFW_LOG_BE0_DATA_OFFSET(r6)	
	blr

/*****************************************************************************
 * writeNVRAMbyte:	write next log into NVRAM
 *					
 *
 *	input:	
 *		R3 - byte to be written
 *		R4 - NVRAM Base Address
 *
 *	output:	
 *		R3 - byte that was written
 *		R4 - NVRAM Base Address 
 *
 * 	Modifies Register:	R3, R4, R5, R6
 ****************************************************************************/
ENTRY(writeLogByteBE1)
	li	r6, LLFW_LOG_BE0_LENGTH
	mulli	r6, r6, 0x10
	add	r4, r6, r4
	NVRAM_POINTER_DATASIZE_BE1( r5, r6, r4)	// get pointer,size of data
	NVRAM_LOG_DATA_OVERFLOW( r5, r6)	// check for overflow
	addi    r5, r5, 1                       // increment pointer
	stw     r5, LLFW_LOG_POS_POINTER(r4)    // store pointer
	addi    r5, r5, -1			// restore old pointer
	add     r6, r4, r5                      // byte address in data section 

	stb 	r3, LLFW_LOG_BE1_DATA_OFFSET(r6)	
	blr

/*****************************************************************************
 * calPartitionHeaderChecksum: 	calculate the Checksum of the 
 *	Partition Header as described in ....
 *
 *	input: r3 - NVRAM BASE adresse
 *
 *	output:	R3 - the calculated checksum as 8 bit value 
 *			R4 - NVRAM log address
 *
 *	Modifies Register:	R3, R4, R5, R6
 ****************************************************************************/
ASM_ENTRY(.calPartitionHeaderChecksum)
	mr	r6, r3
	lbz 	r3,0(r6)			// load first byte
	LOAD64( r4, LLFW_LOG_POS_LENGTH)	// load position of 3rd byte
.L6:
	lbzx 	r5, r4, r6			// r5  nexed byte
	addi 	r4, r4, 1			// r4++ (index)
	add 	r5, r5, r3			// r5 new sum =sum +  nexed byte
	rldicl 	r5, r5, 0, 56
	cmpld 	7, r5, r3					
	cmpldi 	6, r4, LLFW_LOG_POS_DATA_OFFSET
	bge+ 	7,.L5				// if new sum > sum 
	addi 	r5, r5, 1			// new sum ++
	rldicl	r5, r5, 0, 56
.L5:
	mr 	r3,r5				// sum = new sum
	blt+ 	6,.L6

	mr r4, r6
	blr

#else	/* defined(DISABLE_NVRAM) || defined(RTAS_NVRAM) */

ASM_ENTRY(.writeNVRAMbyte)
	ENTRY(writeLogByte)
	blr

#endif