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