]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/efi/iso.c
merge
[plan9front.git] / sys / src / boot / efi / iso.c
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_PROTOCO_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
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
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
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
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(readn(ex, &d, Dirsz) != Dirsz)
133                         break;
134                 if(d.dirlen == 0)
135                         break;
136                 if(readn(ex, name, d.namelen) != d.namelen)
137                         break;
138                 i = d.dirlen - (Dirsz + d.namelen);
139                 while(i-- > 0)
140                         read(ex, &c, 1);
141                 for(i=0; i<d.namelen; i++){
142                         c = name[i];
143                         if(c >= 'A' && c <= 'Z'){
144                                 c -= 'A';
145                                 c += 'a';
146                         }
147                         name[i] = c;
148                 }
149                 name[i] = 0;
150                 while(*path == '/')
151                         path++;
152                 if((end = strchr(path, '/')) == 0)
153                         end = path + strlen(path);
154                 i = end - path;
155                 if(d.namelen == i && memcmp(name, path, i) == 0){
156                         ex->rp = ex->ep;
157                         ex->lba = *((ulong*)d.lba);
158                         ex->len = *((ulong*)d.len);
159                         if(*end == 0)
160                                 return 0;
161                         else if(d.flags[0] & 2){
162                                 path = end;
163                                 continue;
164                         }
165                         break;
166                 }
167         }
168         return -1;
169 }
170
171 static void*
172 isoopen(char *path)
173 {
174         static uchar buf[sizeof(Extend)+8];
175         Extend *ex = (Extend*)((uintptr)(buf+7)&~7);
176
177         if(isowalk(ex, path))
178                 return nil;
179         return ex;
180 }
181
182 int
183 isoinit(void **fp)
184 {
185         EFI_BLOCK_IO_MEDIA *media;
186         EFI_HANDLE *Handles;
187         UINTN Count;
188         int i;
189
190         bio = nil;
191         Count = 0;
192         Handles = nil;
193         if(eficall(ST->BootServices->LocateHandleBuffer,
194                 ByProtocol, &EFI_BLOCK_IO_PROTOCO_GUID, nil, &Count, &Handles))
195                 return -1;
196
197         for(i=0; i<Count; i++){
198                 bio = nil;
199                 if(eficall(ST->BootServices->HandleProtocol,
200                         Handles[i], &EFI_BLOCK_IO_PROTOCO_GUID, &bio))
201                         continue;
202         
203                 media = bio->Media;
204                 if(media != nil
205                 && media->MediaPresent
206                 && media->LogicalPartition == 0
207                 && media->BlockSize != 0
208                 && isoopen("") != nil)
209                         goto Found;
210         }
211         return -1;
212
213 Found:
214         open = isoopen;
215         read = isoread;
216         close = isoclose;
217
218         if(fp != nil)
219                 *fp = isoopen("/cfg/plan9.ini");
220
221         return 0;
222 }