ref: ad1924edab6c591647f30f0f3310c24f638c78c8
dir: /sys/src/boot/efi/iso.c/
#include <u.h>
#include "fns.h"
#include "efi.h"
enum {
Sectsz = 0x800,
Dirsz = 33,
};
typedef struct Extend Extend;
typedef struct Dir Dir;
struct Extend
{
ulong lba;
ulong len;
uchar *rp;
uchar *ep;
uchar buf[Sectsz];
};
struct Dir
{
uchar dirlen;
uchar extlen;
uchar lba[8];
uchar len[8];
uchar date[7];
uchar flags[3];
uchar seq[4];
uchar namelen;
};
typedef struct {
UINT32 MediaId;
BOOLEAN RemovableMedia;
BOOLEAN MediaPresent;
BOOLEAN LogicalPartition;
BOOLEAN ReadOnly;
BOOLEAN WriteCaching;
BOOLEAN Pad[3];
UINT32 BlockSize;
UINT32 IoAlign;
UINT64 LastBlock;
} EFI_BLOCK_IO_MEDIA;
typedef struct {
UINT64 Revision;
EFI_BLOCK_IO_MEDIA *Media;
void *Reset;
void *ReadBlocks;
void *WriteBlocks;
void *FlushBlocks;
} EFI_BLOCK_IO_PROTOCOL;
static EFI_GUID
EFI_BLOCK_IO_PROTOCOL_GUID = {
0x964e5b21, 0x6459, 0x11d2,
0x8e, 0x39, 0x00, 0xa0,
0xc9, 0x69, 0x72, 0x3b,
};
static EFI_BLOCK_IO_PROTOCOL *bio;
static int
readsect(ulong lba, void *buf)
{
lba *= Sectsz/bio->Media->BlockSize;
return eficall(bio->ReadBlocks, bio, (UINTN)bio->Media->MediaId, (UINT64)lba, (UINTN)Sectsz, buf);
}
static int
isoread(void *f, void *data, int len)
{
Extend *ex = f;
if(ex->len > 0 && ex->rp >= ex->ep)
if(readsect(ex->lba++, ex->rp = ex->buf))
return -1;
if(ex->len < len)
len = ex->len;
if(len > (ex->ep - ex->rp))
len = ex->ep - ex->rp;
memmove(data, ex->rp, len);
ex->rp += len;
ex->len -= len;
return len;
}
void
isoclose(void *f)
{
Extend *ex = f;
ex->lba = 0;
ex->len = 0;
ex->rp = ex->ep = ex->buf + Sectsz;
}
static int
isowalk(Extend *ex, char *path)
{
char name[MAXPATH], c, *end;
int i;
Dir d;
isoclose(ex);
/* find pvd */
for(i=0x10; i<0x1000; i++){
if(readsect(i, ex->buf))
return -1;
if(memcmp(ex->buf, "\001CD001\001", 7) == 0)
goto Foundpvd;
}
return -1;
Foundpvd:
ex->lba = *((ulong*)(ex->buf + 156 + 2));
ex->len = *((ulong*)(ex->buf + 156 + 10));
if(*path == 0)
return 0;
for(;;){
if(read(ex, &d.dirlen, 1) != 1)
break;
if(d.dirlen == 0)
continue; /* zero padding to next sector */
if(read(ex, &d.dirlen + 1, Dirsz-1) != Dirsz-1)
break;
if(read(ex, name, d.namelen) != d.namelen)
break;
i = d.dirlen - (Dirsz + d.namelen);
while(i-- > 0){
if(read(ex, &c, 1) != 1)
break;
}
for(i=0; i<d.namelen; i++){
c = name[i];
if(c >= 'A' && c <= 'Z'){
c -= 'A';
c += 'a';
}
name[i] = c;
}
name[i] = 0;
while(*path == '/')
path++;
if((end = strchr(path, '/')) == 0)
end = path + strlen(path);
i = end - path;
if(d.namelen == i && memcmp(name, path, i) == 0){
ex->rp = ex->ep;
ex->lba = *((ulong*)d.lba);
ex->len = *((ulong*)d.len);
if(*end == 0)
return 0;
else if(d.flags[0] & 2){
path = end;
continue;
}
break;
}
}
return -1;
}
static void*
isoopen(char *path)
{
static uchar buf[sizeof(Extend)+8];
Extend *ex = (Extend*)((uintptr)(buf+7)&~7);
if(isowalk(ex, path))
return nil;
return ex;
}
int
isoinit(void **fp)
{
EFI_BLOCK_IO_MEDIA *media;
EFI_HANDLE *Handles;
UINTN Count;
int i;
bio = nil;
Count = 0;
Handles = nil;
if(eficall(ST->BootServices->LocateHandleBuffer,
ByProtocol, &EFI_BLOCK_IO_PROTOCOL_GUID, nil, &Count, &Handles))
return -1;
for(i=0; i<Count; i++){
bio = nil;
if(eficall(ST->BootServices->HandleProtocol,
Handles[i], &EFI_BLOCK_IO_PROTOCOL_GUID, &bio))
continue;
media = bio->Media;
if(media != nil
&& media->MediaPresent
&& media->LogicalPartition == 0
&& media->BlockSize != 0
&& isoopen("") != nil)
goto Found;
}
return -1;
Found:
open = isoopen;
read = isoread;
close = isoclose;
if(fp != nil)
*fp = isoopen("/cfg/plan9.ini");
return 0;
}