summaryrefslogtreecommitdiff
path: root/src/arch/x86/walkcbfs.S
blob: ded65587ec8d734e6f83cf4aef8b576c890fb328 (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
/*
 * This file is part of the coreboot project.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#define CBFS_HEADER_PTR 0xfffffffc

#define CBFS_HEADER_MAGIC 0
#define CBFS_HEADER_VERSION (CBFS_HEADER_MAGIC + 4)
#define CBFS_HEADER_ROMSIZE (CBFS_HEADER_VERSION + 4)
#define CBFS_HEADER_BOOTBLOCKSIZE (CBFS_HEADER_ROMSIZE + 4)
#define CBFS_HEADER_ALIGN (CBFS_HEADER_BOOTBLOCKSIZE + 4)
#define CBFS_HEADER_OFFSET (CBFS_HEADER_ALIGN + 4)

/* we use this instead of CBFS_HEADER_ALIGN because the latter is retired. */
#define CBFS_ALIGNMENT 64

#define CBFS_FILE_MAGIC 0
#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8)
#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4)
#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4)
#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4)

#define CBFS_FILE_STRUCTSIZE (CBFS_FILE_OFFSET + 4)

.section .text
.global walkcbfs_asm

/*
 * input %esi: filename
 * input %esp: return address (not pointer to return address!)
 * output %eax: pointer to CBFS header
 * clobbers %ebx, %ecx, %edi
 */
walkcbfs_asm:
	cld

	mov CBFS_HEADER_PTR, %eax
	mov CBFS_HEADER_ROMSIZE(%eax), %ecx
	bswap %ecx
	mov $0, %ebx
	sub %ecx, %ebx	/* ROM base address in ebx */
	mov CBFS_HEADER_OFFSET(%eax), %ecx
	bswap %ecx
	add %ecx, %ebx	/* address where we start looking for LARCHIVEs */

	/* determine filename length */
	mov $0, %eax
1:
	cmpb $0, (%eax,%esi)
	jz 2f
	add $1, %eax
	jmp 1b
2:
	add $1, %eax
walker:
	mov 0(%ebx), %edi /* Check for LARCHIVE header */
	cmp %edi, filemagic
	jne searchfile
	mov 4(%ebx), %edi
	cmp %edi, filemagic+4
	jne searchfile

	/* LARCHIVE header found */
	mov %ebx, %edi
	add $CBFS_FILE_STRUCTSIZE, %edi /* edi = address of first byte after
					 * struct cbfs_file
					 */
	mov %eax, %ecx
	repe cmpsb
	/* zero flag set if strings are equal */
	jnz tryharder

	/* we found it! */
	mov %ebx, %eax
	jmp *%esp

tryharder:
	sub %ebx, %edi
	sub $CBFS_FILE_STRUCTSIZE, %edi /* edi = # of walked bytes */
	sub %edi, %esi /* esi = start of filename */

	/* ebx = ecx = (current+offset+len+ALIGN-1) & ~(ALIGN-1) */
	mov CBFS_FILE_OFFSET(%ebx), %ecx
	bswap %ecx
	add %ebx, %ecx
	mov CBFS_FILE_LEN(%ebx), %edi
	bswap %edi
	add %edi, %ecx
	/* round by 64 bytes */
	add $(CBFS_ALIGNMENT - 1), %ecx
	and $~(CBFS_ALIGNMENT - 1), %ecx

	/* if oldaddr >= addr, leave */
	cmp %ebx, %ecx
	jbe out

	mov %ecx, %ebx

check_for_exit:
	/* look if we should exit: did we pass into the bootblock already? */
	mov CBFS_HEADER_PTR, %ecx
	mov CBFS_HEADER_BOOTBLOCKSIZE(%ecx), %ecx
	bswap %ecx
	not %ecx
	add $1, %ecx

	cmp %ecx, %ebx
	/* if bootblockstart >= addr (==we're still in the data area),
	 * jump back
	 */
	jbe walker

out:
	mov $0, %eax
	jmp *%esp


searchfile:
	/* if filemagic isn't found, move forward 64 bytes */
	add $CBFS_ALIGNMENT, %ebx
	jmp check_for_exit

filemagic:
	.ascii "LARCHIVE"