ref: 13b1ea74932158069ab1f4c584db81477d9f3551
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; }