xref: /plan9-contrib/sys/src/nboot/efi/iso.c (revision 529c1f209803c78c4f2cda11b13818a57f01c872)
1 #include <u.h>
2 #include "fns.h"
3 #include "efi.h"
4 
5 enum {
6 	Sectsz = 0x800,
7 	Dirsz = 33,
8 };
9 
10 typedef struct Extend Extend;
11 typedef struct Dir Dir;
12 
13 struct Extend
14 {
15 	ulong lba;
16 	ulong len;
17 	uchar *rp;
18 	uchar *ep;
19 	uchar buf[Sectsz];
20 };
21 
22 struct Dir
23 {
24 	uchar dirlen;
25 	uchar extlen;
26 
27 	uchar lba[8];
28 	uchar len[8];
29 
30 	uchar date[7];
31 
32 	uchar flags[3];
33 
34 	uchar seq[4];
35 
36 	uchar namelen;
37 };
38 
39 typedef struct {
40 	UINT32		MediaId;
41 
42 	BOOLEAN		RemovableMedia;
43 	BOOLEAN		MediaPresent;
44 	BOOLEAN		LogicalPartition;
45 	BOOLEAN		ReadOnly;
46 
47 	BOOLEAN		WriteCaching;
48 	BOOLEAN		Pad[3];
49 
50 	UINT32		BlockSize;
51 	UINT32		IoAlign;
52 	UINT64		LastBlock;
53 } EFI_BLOCK_IO_MEDIA;
54 
55 typedef struct {
56 	UINT64		Revision;
57 	EFI_BLOCK_IO_MEDIA	*Media;
58 	void		*Reset;
59 	void		*ReadBlocks;
60 	void		*WriteBlocks;
61 	void		*FlushBlocks;
62 } EFI_BLOCK_IO_PROTOCOL;
63 
64 static EFI_GUID
65 EFI_BLOCK_IO_PROTOCOL_GUID = {
66 	0x964e5b21, 0x6459, 0x11d2,
67 	0x8e, 0x39, 0x00, 0xa0,
68 	0xc9, 0x69, 0x72, 0x3b,
69 };
70 
71 static EFI_BLOCK_IO_PROTOCOL *bio;
72 
73 static int
readsect(ulong lba,void * buf)74 readsect(ulong lba, void *buf)
75 {
76 	lba *= Sectsz/bio->Media->BlockSize;
77 	return eficall(bio->ReadBlocks, bio, (UINTN)bio->Media->MediaId, (UINT64)lba, (UINTN)Sectsz, buf);
78 }
79 
80 static int
isoread(void * f,void * data,int len)81 isoread(void *f, void *data, int len)
82 {
83 	Extend *ex = f;
84 
85 	if(ex->len > 0 && ex->rp >= ex->ep)
86 		if(readsect(ex->lba++, ex->rp = ex->buf))
87 			return -1;
88 	if(ex->len < len)
89 		len = ex->len;
90 	if(len > (ex->ep - ex->rp))
91 		len = ex->ep - ex->rp;
92 	memmove(data, ex->rp, len);
93 	ex->rp += len;
94 	ex->len -= len;
95 	return len;
96 }
97 
98 void
isoclose(void * f)99 isoclose(void *f)
100 {
101 	Extend *ex = f;
102 
103 	ex->lba = 0;
104 	ex->len = 0;
105 	ex->rp = ex->ep = ex->buf + Sectsz;
106 }
107 
108 static int
isowalk(Extend * ex,char * path)109 isowalk(Extend *ex, char *path)
110 {
111 	char name[MAXPATH], c, *end;
112 	int i;
113 	Dir d;
114 
115 	isoclose(ex);
116 
117 	/* find pvd */
118 	for(i=0x10; i<0x1000; i++){
119 		if(readsect(i, ex->buf))
120 			return -1;
121 		if(memcmp(ex->buf, "\001CD001\001", 7) == 0)
122 			goto Foundpvd;
123 	}
124 	return -1;
125 Foundpvd:
126 	ex->lba = *((ulong*)(ex->buf + 156 + 2));
127 	ex->len = *((ulong*)(ex->buf + 156 + 10));
128 	if(*path == 0)
129 		return 0;
130 
131 	for(;;){
132 		if(read(ex, &d.dirlen, 1) != 1)
133 			break;
134 		if(d.dirlen == 0)
135 			continue;	/* zero padding to next sector */
136 		if(read(ex, &d.dirlen + 1, Dirsz-1) != Dirsz-1)
137 			break;
138 		if(read(ex, name, d.namelen) != d.namelen)
139 			break;
140 		i = d.dirlen - (Dirsz + d.namelen);
141 		while(i-- > 0){
142 			if(read(ex, &c, 1) != 1)
143 				break;
144 		}
145 		for(i=0; i<d.namelen; i++){
146 			c = name[i];
147 			if(c >= 'A' && c <= 'Z'){
148 				c -= 'A';
149 				c += 'a';
150 			}
151 			name[i] = c;
152 		}
153 		name[i] = 0;
154 		while(*path == '/')
155 			path++;
156 		if((end = strchr(path, '/')) == 0)
157 			end = path + strlen(path);
158 		i = end - path;
159 		if(d.namelen == i && memcmp(name, path, i) == 0){
160 			ex->rp = ex->ep;
161 			ex->lba = *((ulong*)d.lba);
162 			ex->len = *((ulong*)d.len);
163 			if(*end == 0)
164 				return 0;
165 			else if(d.flags[0] & 2){
166 				path = end;
167 				continue;
168 			}
169 			break;
170 		}
171 	}
172 	return -1;
173 }
174 
175 static void*
isoopen(char * path)176 isoopen(char *path)
177 {
178 	static uchar buf[sizeof(Extend)+8];
179 	Extend *ex = (Extend*)((uintptr)(buf+7)&~7);
180 
181 	if(isowalk(ex, path))
182 		return nil;
183 	return ex;
184 }
185 
186 int
isoinit(void ** fp)187 isoinit(void **fp)
188 {
189 	EFI_BLOCK_IO_MEDIA *media;
190 	EFI_HANDLE *Handles;
191 	UINTN Count;
192 	int i;
193 
194 	bio = nil;
195 	Count = 0;
196 	Handles = nil;
197 	if(eficall(ST->BootServices->LocateHandleBuffer,
198 		ByProtocol, &EFI_BLOCK_IO_PROTOCOL_GUID, nil, &Count, &Handles))
199 		return -1;
200 
201 	for(i=0; i<Count; i++){
202 		bio = nil;
203 		if(eficall(ST->BootServices->HandleProtocol,
204 			Handles[i], &EFI_BLOCK_IO_PROTOCOL_GUID, &bio))
205 			continue;
206 
207 		media = bio->Media;
208 		if(media != nil
209 		&& media->MediaPresent
210 		&& media->LogicalPartition == 0
211 		&& media->BlockSize != 0
212 		&& isoopen("") != nil)
213 			goto Found;
214 	}
215 	return -1;
216 
217 Found:
218 	open = isoopen;
219 	read = isoread;
220 	close = isoclose;
221 
222 	if(fp != nil)
223 		*fp = isoopen("/cfg/plan9.ini");
224 
225 	return 0;
226 }
227