1*37da2899SCharles.Forsyth# 2*37da2899SCharles.Forsyth# basic Flash Translation Layer driver 3*37da2899SCharles.Forsyth# see for instance the Intel technical paper 4*37da2899SCharles.Forsyth# ``Understanding the Flash Translation Layer (FTL) Specification'' 5*37da2899SCharles.Forsyth# Order number 297816-001 (online at www.intel.com) 6*37da2899SCharles.Forsyth# 7*37da2899SCharles.Forsyth# a public driver by David Hinds, dhinds@allegro.stanford.edu 8*37da2899SCharles.Forsyth# further helps with some details. 9*37da2899SCharles.Forsyth# 10*37da2899SCharles.Forsyth# this driver uses the common simplification of never storing 11*37da2899SCharles.Forsyth# the VBM on the medium (a waste of precious flash!) but 12*37da2899SCharles.Forsyth# rather building it on the fly as the block maps are read. 13*37da2899SCharles.Forsyth# 14*37da2899SCharles.Forsyth# Plan 9 driver (c) 1997 by C H Forsyth (forsyth@caldo.demon.co.uk) 15*37da2899SCharles.Forsyth# This driver may be used or adapted by anyone for any non-commercial purpose. 16*37da2899SCharles.Forsyth# 17*37da2899SCharles.Forsyth# adapted for Inferno 1998 by C H Forsyth, Vita Nuova Limited, York, England (byteles@vitanuova.com) 18*37da2899SCharles.Forsyth# 19*37da2899SCharles.Forsyth# C H Forsyth and Vita Nuova Limited expressly allow Lucent Technologies 20*37da2899SCharles.Forsyth# to use this driver freely for any Inferno-related purposes whatever, 21*37da2899SCharles.Forsyth# including commercial applications. 22*37da2899SCharles.Forsyth# 23*37da2899SCharles.Forsyth# TO DO: 24*37da2899SCharles.Forsyth# check error handling details for get/put flash 25*37da2899SCharles.Forsyth# bad block handling 26*37da2899SCharles.Forsyth# reserved space in formatted size 27*37da2899SCharles.Forsyth# possibly block size as parameter 28*37da2899SCharles.Forsyth# fetch parameters from header on init 29*37da2899SCharles.Forsyth# 30*37da2899SCharles.Forsyth# Adapted to a ftl formatter for Inferno 2000 by J R Firth, Vita Nuova Limited 31*37da2899SCharles.Forsyth# usage : ftl flashsize secsize inputfile outputfile 32*37da2899SCharles.Forsyth# outputfile will then be a ftl image of inputfile 33*37da2899SCharles.Forsyth# nb assumes the base address is zero 34*37da2899SCharles.Forsyth# 35*37da2899SCharles.Forsyth# Converted to limbo for Inferno 2000 by JR Firth, Vita Nuova Holdings Limited 36*37da2899SCharles.Forsyth# 37*37da2899SCharles.Forsyth 38*37da2899SCharles.Forsythimplement Ftlimage; 39*37da2899SCharles.Forsyth 40*37da2899SCharles.Forsythinclude "sys.m"; 41*37da2899SCharles.Forsythinclude "draw.m"; 42*37da2899SCharles.Forsyth 43*37da2899SCharles.Forsythsys : Sys; 44*37da2899SCharles.Forsyth OREAD, OWRITE, FD, open, create, read, write, print, fprint : import sys; 45*37da2899SCharles.Forsyth 46*37da2899SCharles.ForsythFtlimage : module 47*37da2899SCharles.Forsyth{ 48*37da2899SCharles.Forsyth init : fn(nil : ref Draw->Context, argv : list of string); 49*37da2899SCharles.Forsyth}; 50*37da2899SCharles.Forsyth 51*37da2899SCharles.Forsythstderr : ref FD; 52*37da2899SCharles.Forsyth 53*37da2899SCharles.Forsythflashsize, secsize : int; 54*37da2899SCharles.Forsythflashm : array of byte; 55*37da2899SCharles.Forsythtrace : int = 0; 56*37da2899SCharles.Forsyth 57*37da2899SCharles.ForsythEshift : con 18; # 2^18=256k; log2(eraseunit) 58*37da2899SCharles.ForsythFlashseg : con 1<<Eshift; 59*37da2899SCharles.ForsythBshift : con 9; # 2^9=512 60*37da2899SCharles.ForsythBsize : con 1<<Bshift; 61*37da2899SCharles.ForsythBAMoffset : con 16r100; 62*37da2899SCharles.ForsythNolimit : con ~0; 63*37da2899SCharles.ForsythUSABLEPCT : con 95; # release only this % to client 64*37da2899SCharles.Forsyth 65*37da2899SCharles.ForsythFTLDEBUG : con 0; 66*37da2899SCharles.Forsyth 67*37da2899SCharles.Forsyth# erase unit header (defined by FTL specification) 68*37da2899SCharles.Forsyth# offsets into Merase 69*37da2899SCharles.ForsythO_LINKTUPLE : con 0; 70*37da2899SCharles.ForsythO_ORGTUPLE : con 5; 71*37da2899SCharles.ForsythO_NXFER : con 15; 72*37da2899SCharles.ForsythO_NERASE : con 16; 73*37da2899SCharles.ForsythO_ID : con 20; 74*37da2899SCharles.ForsythO_BSHIFT : con 22; 75*37da2899SCharles.ForsythO_ESHIFT : con 23; 76*37da2899SCharles.ForsythO_PSTART : con 24; 77*37da2899SCharles.ForsythO_NUNITS : con 26; 78*37da2899SCharles.ForsythO_PSIZE : con 28; 79*37da2899SCharles.ForsythO_VBMBASE : con 32; 80*37da2899SCharles.ForsythO_NVBM : con 36; 81*37da2899SCharles.ForsythO_FLAGS : con 38; 82*37da2899SCharles.ForsythO_CODE : con 39; 83*37da2899SCharles.ForsythO_SERIAL : con 40; 84*37da2899SCharles.ForsythO_ALTOFFSET : con 44; 85*37da2899SCharles.ForsythO_BAMOFFSET : con 48; 86*37da2899SCharles.ForsythO_RSV2 : con 52; 87*37da2899SCharles.Forsyth 88*37da2899SCharles.ForsythERASEHDRLEN : con 64; 89*37da2899SCharles.Forsyth 90*37da2899SCharles.Forsyth# special unit IDs 91*37da2899SCharles.ForsythXferID : con 16rffff; 92*37da2899SCharles.ForsythXferBusy : con 16r7fff; 93*37da2899SCharles.Forsyth 94*37da2899SCharles.Forsyth# special BAM addresses 95*37da2899SCharles.ForsythBfree : con -1; #16rffffffff 96*37da2899SCharles.ForsythBwriting : con -2; #16rfffffffe 97*37da2899SCharles.ForsythBdeleted : con 0; 98*37da2899SCharles.Forsyth 99*37da2899SCharles.Forsyth# block types 100*37da2899SCharles.ForsythTypeShift : con 7; 101*37da2899SCharles.ForsythBlockType : con (1<<TypeShift)-1; 102*37da2899SCharles.ForsythControlBlock : con 16r30; 103*37da2899SCharles.ForsythDataBlock : con 16r40; 104*37da2899SCharles.ForsythReplacePage : con 16r60; 105*37da2899SCharles.ForsythBadBlock : con 16r70; 106*37da2899SCharles.Forsyth 107*37da2899SCharles.ForsythBNO(va : int) : int 108*37da2899SCharles.Forsyth{ 109*37da2899SCharles.Forsyth return va>>Bshift; 110*37da2899SCharles.Forsyth} 111*37da2899SCharles.ForsythMKBAM(b : int,t : int) : int 112*37da2899SCharles.Forsyth{ 113*37da2899SCharles.Forsyth return (b<<Bshift)|t; 114*37da2899SCharles.Forsyth} 115*37da2899SCharles.Forsyth 116*37da2899SCharles.ForsythTerase : adt { 117*37da2899SCharles.Forsyth x : int; 118*37da2899SCharles.Forsyth id : int; 119*37da2899SCharles.Forsyth offset : int; 120*37da2899SCharles.Forsyth bamoffset : int; 121*37da2899SCharles.Forsyth nbam : int; 122*37da2899SCharles.Forsyth bam : array of byte; 123*37da2899SCharles.Forsyth bamx : int; 124*37da2899SCharles.Forsyth nfree : int; 125*37da2899SCharles.Forsyth nused : int; 126*37da2899SCharles.Forsyth ndead : int; 127*37da2899SCharles.Forsyth nbad : int; 128*37da2899SCharles.Forsyth nerase : int; 129*37da2899SCharles.Forsyth}; 130*37da2899SCharles.Forsyth 131*37da2899SCharles.ForsythFtl : adt { 132*37da2899SCharles.Forsyth base : int; # base of flash region 133*37da2899SCharles.Forsyth size : int; # size of flash region 134*37da2899SCharles.Forsyth segsize : int; # size of flash segment (erase unit) 135*37da2899SCharles.Forsyth eshift : int; # log2(erase-unit-size) 136*37da2899SCharles.Forsyth bshift : int; # log2(bsize) 137*37da2899SCharles.Forsyth bsize : int; 138*37da2899SCharles.Forsyth nunit : int; # number of segments (erase units) 139*37da2899SCharles.Forsyth unit : array of ref Terase; 140*37da2899SCharles.Forsyth lastx : int; # index in unit of last allocation 141*37da2899SCharles.Forsyth xfer : int; # index in unit of current transfer unit (-1 if none) 142*37da2899SCharles.Forsyth nfree : int; # total free space in blocks 143*37da2899SCharles.Forsyth nblock : int; # total space in blocks 144*37da2899SCharles.Forsyth rwlimit : int; # user-visible block limit (`formatted size') 145*37da2899SCharles.Forsyth vbm : array of int; # virtual block map 146*37da2899SCharles.Forsyth fstart : int; # address of first block of data in a segment 147*37da2899SCharles.Forsyth trace : int; # (debugging) trace of read/write actions 148*37da2899SCharles.Forsyth detach : int; # free Ftl on last close 149*37da2899SCharles.Forsyth 150*37da2899SCharles.Forsyth # scavenging variables 151*37da2899SCharles.Forsyth needspace : int; 152*37da2899SCharles.Forsyth hasproc : int; 153*37da2899SCharles.Forsyth}; 154*37da2899SCharles.Forsyth 155*37da2899SCharles.Forsyth# Ftl.detach 156*37da2899SCharles.ForsythDetached : con 1; # detach on close 157*37da2899SCharles.ForsythDeferred : con 2; # scavenger must free it 158*37da2899SCharles.Forsyth 159*37da2899SCharles.Forsythftls : ref Ftl; 160*37da2899SCharles.Forsyth 161*37da2899SCharles.Forsythftlstat(sz : int) 162*37da2899SCharles.Forsyth{ 163*37da2899SCharles.Forsyth print("16r%x:16r%x:16r%x\n", ftls.rwlimit*Bsize, sz, flashsize); 164*37da2899SCharles.Forsyth print("%d:%d:%d in 512b blocks\n", ftls.rwlimit, sz>>Bshift, flashsize>>Bshift); 165*37da2899SCharles.Forsyth} 166*37da2899SCharles.Forsyth 167*37da2899SCharles.Forsythftlread(buf : array of byte, n : int, offset : int) : int 168*37da2899SCharles.Forsyth{ 169*37da2899SCharles.Forsyth ftl : ref Ftl; 170*37da2899SCharles.Forsyth e : ref Terase; 171*37da2899SCharles.Forsyth nb : int; 172*37da2899SCharles.Forsyth a : int; 173*37da2899SCharles.Forsyth pb : int; 174*37da2899SCharles.Forsyth mapb : int; 175*37da2899SCharles.Forsyth 176*37da2899SCharles.Forsyth if(n <= 0 || n%Bsize || offset%Bsize) { 177*37da2899SCharles.Forsyth fprint(stderr, "ftl: bad read\n"); 178*37da2899SCharles.Forsyth exit; 179*37da2899SCharles.Forsyth } 180*37da2899SCharles.Forsyth ftl = ftls; 181*37da2899SCharles.Forsyth nb = n/Bsize; 182*37da2899SCharles.Forsyth offset /= Bsize; 183*37da2899SCharles.Forsyth if(offset >= ftl.rwlimit) 184*37da2899SCharles.Forsyth return 0; 185*37da2899SCharles.Forsyth if(offset+nb > ftl.rwlimit) 186*37da2899SCharles.Forsyth nb = ftl.rwlimit - offset; 187*37da2899SCharles.Forsyth a = 0; 188*37da2899SCharles.Forsyth for(n = 0; n < nb; n++){ 189*37da2899SCharles.Forsyth (mapb, e, pb) = mapblk(ftl, offset+n); 190*37da2899SCharles.Forsyth if(mapb) 191*37da2899SCharles.Forsyth getflash(ftl, buf[a:], e.offset + pb*Bsize, Bsize); 192*37da2899SCharles.Forsyth else 193*37da2899SCharles.Forsyth memset(buf[a:], 0, Bsize); 194*37da2899SCharles.Forsyth a += Bsize; 195*37da2899SCharles.Forsyth } 196*37da2899SCharles.Forsyth return a; 197*37da2899SCharles.Forsyth} 198*37da2899SCharles.Forsyth 199*37da2899SCharles.Forsythftlwrite(buf : array of byte, n : int, offset : int) : int 200*37da2899SCharles.Forsyth{ 201*37da2899SCharles.Forsyth ns, nb : int; 202*37da2899SCharles.Forsyth a : int; 203*37da2899SCharles.Forsyth e, oe : ref Terase; 204*37da2899SCharles.Forsyth ob, v : int; 205*37da2899SCharles.Forsyth ftl : ref Ftl; 206*37da2899SCharles.Forsyth mapb : int; 207*37da2899SCharles.Forsyth 208*37da2899SCharles.Forsyth if(n <= 0) 209*37da2899SCharles.Forsyth return 0; 210*37da2899SCharles.Forsyth ftl = ftls; 211*37da2899SCharles.Forsyth if(n <= 0 || n%Bsize || offset%Bsize) { 212*37da2899SCharles.Forsyth fprint(stderr, "ftl: bad write\n"); 213*37da2899SCharles.Forsyth exit; 214*37da2899SCharles.Forsyth } 215*37da2899SCharles.Forsyth nb = n/Bsize; 216*37da2899SCharles.Forsyth offset /= Bsize; 217*37da2899SCharles.Forsyth if(offset >= ftl.rwlimit) 218*37da2899SCharles.Forsyth return 0; 219*37da2899SCharles.Forsyth if(offset+nb > ftl.rwlimit) 220*37da2899SCharles.Forsyth nb = ftl.rwlimit - offset; 221*37da2899SCharles.Forsyth a = 0; 222*37da2899SCharles.Forsyth for(n = 0; n < nb; n++){ 223*37da2899SCharles.Forsyth ns = 0; 224*37da2899SCharles.Forsyth while((v = allocblk(ftl)) == 0) 225*37da2899SCharles.Forsyth if(!scavenge(ftl) || ++ns > 3){ 226*37da2899SCharles.Forsyth fprint(stderr, "ftl: flash memory full\n"); 227*37da2899SCharles.Forsyth } 228*37da2899SCharles.Forsyth (mapb, oe, ob) = mapblk(ftl, offset+n); 229*37da2899SCharles.Forsyth if(!mapb) 230*37da2899SCharles.Forsyth oe = nil; 231*37da2899SCharles.Forsyth e = ftl.unit[v>>16]; 232*37da2899SCharles.Forsyth v &= 16rffff; 233*37da2899SCharles.Forsyth putflash(ftl, e.offset + v*Bsize, buf[a:], Bsize); 234*37da2899SCharles.Forsyth putbam(ftl, e, v, MKBAM(offset+n, DataBlock)); 235*37da2899SCharles.Forsyth # both old and new block references exist in this window (can't be closed?) 236*37da2899SCharles.Forsyth ftl.vbm[offset+n] = (e.x<<16) | v; 237*37da2899SCharles.Forsyth if(oe != nil){ 238*37da2899SCharles.Forsyth putbam(ftl, oe, ob, Bdeleted); 239*37da2899SCharles.Forsyth oe.ndead++; 240*37da2899SCharles.Forsyth } 241*37da2899SCharles.Forsyth a += Bsize; 242*37da2899SCharles.Forsyth } 243*37da2899SCharles.Forsyth return a; 244*37da2899SCharles.Forsyth} 245*37da2899SCharles.Forsyth 246*37da2899SCharles.Forsythmkftl(fname : string, base : int, size : int, eshift : int, op : string) : ref Ftl 247*37da2899SCharles.Forsyth{ 248*37da2899SCharles.Forsyth i, j, nov, segblocks : int; 249*37da2899SCharles.Forsyth limit : int; 250*37da2899SCharles.Forsyth e : ref Terase; 251*37da2899SCharles.Forsyth 252*37da2899SCharles.Forsyth ftl := ref Ftl; 253*37da2899SCharles.Forsyth ftl.lastx = 0; 254*37da2899SCharles.Forsyth ftl.detach = 0; 255*37da2899SCharles.Forsyth ftl.needspace = 0; 256*37da2899SCharles.Forsyth ftl.hasproc = 0; 257*37da2899SCharles.Forsyth ftl.trace = 0; 258*37da2899SCharles.Forsyth limit = flashsize; 259*37da2899SCharles.Forsyth if(size == Nolimit) 260*37da2899SCharles.Forsyth size = limit-base; 261*37da2899SCharles.Forsyth if(base >= limit || size > limit || base+size > limit || eshift < 8 || (1<<eshift) > size) { 262*37da2899SCharles.Forsyth fprint(stderr, "bad flash space parameters"); 263*37da2899SCharles.Forsyth exit; 264*37da2899SCharles.Forsyth } 265*37da2899SCharles.Forsyth if(FTLDEBUG || ftl.trace || trace) 266*37da2899SCharles.Forsyth print("%s flash %s #%x:#%x limit #%x\n", op, fname, base, size, limit); 267*37da2899SCharles.Forsyth ftl.base = base; 268*37da2899SCharles.Forsyth ftl.size = size; 269*37da2899SCharles.Forsyth ftl.bshift = Bshift; 270*37da2899SCharles.Forsyth ftl.bsize = Bsize; 271*37da2899SCharles.Forsyth ftl.eshift = eshift; 272*37da2899SCharles.Forsyth ftl.segsize = 1<<eshift; 273*37da2899SCharles.Forsyth ftl.nunit = size>>eshift; 274*37da2899SCharles.Forsyth nov = ((ftl.segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize; # number of overhead blocks per segment (header, and BAM itself) 275*37da2899SCharles.Forsyth ftl.fstart = nov; 276*37da2899SCharles.Forsyth segblocks = ftl.segsize/Bsize - nov; 277*37da2899SCharles.Forsyth ftl.nblock = ftl.nunit*segblocks; 278*37da2899SCharles.Forsyth if(ftl.nblock >= 16r10000) 279*37da2899SCharles.Forsyth ftl.nblock = 16r10000; 280*37da2899SCharles.Forsyth ftl.vbm = array[ftl.nblock] of int; 281*37da2899SCharles.Forsyth ftl.unit = array[ftl.nunit] of ref Terase; 282*37da2899SCharles.Forsyth if(ftl.vbm == nil || ftl.unit == nil) { 283*37da2899SCharles.Forsyth fprint(stderr, "out of mem"); 284*37da2899SCharles.Forsyth exit; 285*37da2899SCharles.Forsyth } 286*37da2899SCharles.Forsyth for(i=0; i<ftl.nblock; i++) 287*37da2899SCharles.Forsyth ftl.vbm[i] = 0; 288*37da2899SCharles.Forsyth if(op == "format"){ 289*37da2899SCharles.Forsyth for(i=0; i<ftl.nunit-1; i++) 290*37da2899SCharles.Forsyth eraseinit(ftl, i*ftl.segsize, i, 1); 291*37da2899SCharles.Forsyth eraseinit(ftl, i*ftl.segsize, XferID, 1); 292*37da2899SCharles.Forsyth } 293*37da2899SCharles.Forsyth ftl.xfer = -1; 294*37da2899SCharles.Forsyth for(i=0; i<ftl.nunit; i++){ 295*37da2899SCharles.Forsyth e = eraseload(ftl, i, i*ftl.segsize); 296*37da2899SCharles.Forsyth if(e == nil){ 297*37da2899SCharles.Forsyth fprint(stderr, "ftl: logical segment %d: bad format\n", i); 298*37da2899SCharles.Forsyth continue; 299*37da2899SCharles.Forsyth } 300*37da2899SCharles.Forsyth if(e.id == XferBusy){ 301*37da2899SCharles.Forsyth e.nerase++; 302*37da2899SCharles.Forsyth eraseinit(ftl, e.offset, XferID, e.nerase); 303*37da2899SCharles.Forsyth e.id = XferID; 304*37da2899SCharles.Forsyth } 305*37da2899SCharles.Forsyth for(j=0; j<ftl.nunit; j++) 306*37da2899SCharles.Forsyth if(ftl.unit[j] != nil && ftl.unit[j].id == e.id){ 307*37da2899SCharles.Forsyth fprint(stderr, "ftl: duplicate erase unit #%x\n", e.id); 308*37da2899SCharles.Forsyth erasefree(e); 309*37da2899SCharles.Forsyth e = nil; 310*37da2899SCharles.Forsyth break; 311*37da2899SCharles.Forsyth } 312*37da2899SCharles.Forsyth if(e != nil){ 313*37da2899SCharles.Forsyth ftl.unit[e.x] = e; 314*37da2899SCharles.Forsyth if(e.id == XferID) 315*37da2899SCharles.Forsyth ftl.xfer = e.x; 316*37da2899SCharles.Forsyth if (FTLDEBUG || ftl.trace || trace) 317*37da2899SCharles.Forsyth fprint(stderr, "ftl: unit %d:#%x used %d free %d dead %d bad %d nerase %d\n", 318*37da2899SCharles.Forsyth e.x, e.id, e.nused, e.nfree, e.ndead, e.nbad, e.nerase); 319*37da2899SCharles.Forsyth } 320*37da2899SCharles.Forsyth } 321*37da2899SCharles.Forsyth if(ftl.xfer < 0 && ftl.nunit <= 0 || ftl.xfer >= 0 && ftl.nunit <= 1) { 322*37da2899SCharles.Forsyth fprint(stderr, "ftl: no valid flash data units"); 323*37da2899SCharles.Forsyth exit; 324*37da2899SCharles.Forsyth } 325*37da2899SCharles.Forsyth if(ftl.xfer < 0) 326*37da2899SCharles.Forsyth fprint(stderr, "ftl: no transfer unit: device is WORM\n"); 327*37da2899SCharles.Forsyth else 328*37da2899SCharles.Forsyth ftl.nblock -= segblocks; # discount transfer segment 329*37da2899SCharles.Forsyth if(ftl.nblock >= 1000) 330*37da2899SCharles.Forsyth ftl.rwlimit = ftl.nblock-100; # TO DO: variable reserve 331*37da2899SCharles.Forsyth else 332*37da2899SCharles.Forsyth ftl.rwlimit = ftl.nblock*USABLEPCT/100; 333*37da2899SCharles.Forsyth return ftl; 334*37da2899SCharles.Forsyth} 335*37da2899SCharles.Forsyth 336*37da2899SCharles.Forsythftlfree(ftl : ref Ftl) 337*37da2899SCharles.Forsyth{ 338*37da2899SCharles.Forsyth if(ftl != nil){ 339*37da2899SCharles.Forsyth ftl.unit = nil; 340*37da2899SCharles.Forsyth ftl.vbm = nil; 341*37da2899SCharles.Forsyth ftl = nil; 342*37da2899SCharles.Forsyth } 343*37da2899SCharles.Forsyth} 344*37da2899SCharles.Forsyth 345*37da2899SCharles.Forsyth# 346*37da2899SCharles.Forsyth# this simple greedy algorithm weighted by nerase does seem to lead 347*37da2899SCharles.Forsyth# to even wear of erase units (cf. the eNVy file system) 348*37da2899SCharles.Forsyth# 349*37da2899SCharles.Forsyth 350*37da2899SCharles.Forsythbestcopy(ftl : ref Ftl) : ref Terase 351*37da2899SCharles.Forsyth{ 352*37da2899SCharles.Forsyth e, be : ref Terase; 353*37da2899SCharles.Forsyth i : int; 354*37da2899SCharles.Forsyth 355*37da2899SCharles.Forsyth be = nil; 356*37da2899SCharles.Forsyth for(i=0; i<ftl.nunit; i++) 357*37da2899SCharles.Forsyth if((e = ftl.unit[i]) != nil && e.id != XferID && e.id != XferBusy && e.ndead+e.nbad && 358*37da2899SCharles.Forsyth (be == nil || e.nerase <= be.nerase && e.ndead >= be.ndead)) 359*37da2899SCharles.Forsyth be = e; 360*37da2899SCharles.Forsyth return be; 361*37da2899SCharles.Forsyth} 362*37da2899SCharles.Forsyth 363*37da2899SCharles.Forsythcopyunit(ftl : ref Ftl, from : ref Terase, too : ref Terase) : int 364*37da2899SCharles.Forsyth{ 365*37da2899SCharles.Forsyth i, nb : int; 366*37da2899SCharles.Forsyth id := array[2] of byte; 367*37da2899SCharles.Forsyth bam : array of byte; 368*37da2899SCharles.Forsyth buf : array of byte; 369*37da2899SCharles.Forsyth v, bno : int; 370*37da2899SCharles.Forsyth 371*37da2899SCharles.Forsyth if(FTLDEBUG || ftl.trace || trace) 372*37da2899SCharles.Forsyth print("ftl: copying %d (#%x) to #%x\n", from.id, from.offset, too.offset); 373*37da2899SCharles.Forsyth too.nbam = 0; 374*37da2899SCharles.Forsyth too.bam = nil; 375*37da2899SCharles.Forsyth bam = nil; 376*37da2899SCharles.Forsyth buf = array[Bsize] of byte; 377*37da2899SCharles.Forsyth if(buf == nil) 378*37da2899SCharles.Forsyth return 0; 379*37da2899SCharles.Forsyth PUT2(id, XferBusy); 380*37da2899SCharles.Forsyth putflash(ftl, too.offset+O_ID, id, 2); 381*37da2899SCharles.Forsyth # make new BAM 382*37da2899SCharles.Forsyth nb = from.nbam*4; 383*37da2899SCharles.Forsyth bam = array[nb] of byte; 384*37da2899SCharles.Forsyth memmove(bam, from.bam, nb); 385*37da2899SCharles.Forsyth too.nused = 0; 386*37da2899SCharles.Forsyth too.nbad = 0; 387*37da2899SCharles.Forsyth too.nfree = 0; 388*37da2899SCharles.Forsyth too.ndead = 0; 389*37da2899SCharles.Forsyth for(i = 0; i < from.nbam; i++) 390*37da2899SCharles.Forsyth bv := GET4(bam[4*i:]); 391*37da2899SCharles.Forsyth case(bv){ 392*37da2899SCharles.Forsyth Bwriting or 393*37da2899SCharles.Forsyth Bdeleted or 394*37da2899SCharles.Forsyth Bfree => 395*37da2899SCharles.Forsyth PUT4(bam[4*i:], Bfree); 396*37da2899SCharles.Forsyth too.nfree++; 397*37da2899SCharles.Forsyth break; 398*37da2899SCharles.Forsyth * => 399*37da2899SCharles.Forsyth case(bv&BlockType){ 400*37da2899SCharles.Forsyth DataBlock or 401*37da2899SCharles.Forsyth ReplacePage => 402*37da2899SCharles.Forsyth v = bv; 403*37da2899SCharles.Forsyth bno = BNO(v & ~BlockType); 404*37da2899SCharles.Forsyth if(i < ftl.fstart || bno >= ftl.nblock){ 405*37da2899SCharles.Forsyth print("ftl: unit %d:#%x bad bam[%d]=#%x\n", from.x, from.id, i, v); 406*37da2899SCharles.Forsyth too.nfree++; 407*37da2899SCharles.Forsyth PUT4(bam[4*i:], Bfree); 408*37da2899SCharles.Forsyth break; 409*37da2899SCharles.Forsyth } 410*37da2899SCharles.Forsyth getflash(ftl, buf, from.offset+i*Bsize, Bsize); 411*37da2899SCharles.Forsyth putflash(ftl, too.offset+i*Bsize, buf, Bsize); 412*37da2899SCharles.Forsyth too.nused++; 413*37da2899SCharles.Forsyth break; 414*37da2899SCharles.Forsyth ControlBlock => 415*37da2899SCharles.Forsyth too.nused++; 416*37da2899SCharles.Forsyth break; 417*37da2899SCharles.Forsyth * => 418*37da2899SCharles.Forsyth # case BadBlock: # it isn't necessarily bad in this unit 419*37da2899SCharles.Forsyth too.nfree++; 420*37da2899SCharles.Forsyth PUT4(bam[4*i:], Bfree); 421*37da2899SCharles.Forsyth break; 422*37da2899SCharles.Forsyth } 423*37da2899SCharles.Forsyth } 424*37da2899SCharles.Forsyth # for(i=0; i<from.nbam; i++){ 425*37da2899SCharles.Forsyth # v = GET4(bam[4*i:]); 426*37da2899SCharles.Forsyth # if(v != Bfree && ftl.trace > 1) 427*37da2899SCharles.Forsyth # print("to[%d]=#%x\n", i, v); 428*37da2899SCharles.Forsyth # PUT4(bam[4*i:], v); 429*37da2899SCharles.Forsyth # } 430*37da2899SCharles.Forsyth putflash(ftl, too.bamoffset, bam, nb); # BUG: PUT4 ? IS IT ? 431*37da2899SCharles.Forsyth # for(i=0; i<from.nbam; i++){ 432*37da2899SCharles.Forsyth # v = GET4(bam[4*i:]); 433*37da2899SCharles.Forsyth # PUT4(bam[4*i:], v); 434*37da2899SCharles.Forsyth # } 435*37da2899SCharles.Forsyth too.id = from.id; 436*37da2899SCharles.Forsyth PUT2(id, too.id); 437*37da2899SCharles.Forsyth putflash(ftl, too.offset+O_ID, id, 2); 438*37da2899SCharles.Forsyth too.nbam = from.nbam; 439*37da2899SCharles.Forsyth too.bam = bam; 440*37da2899SCharles.Forsyth ftl.nfree += too.nfree - from.nfree; 441*37da2899SCharles.Forsyth buf = nil; 442*37da2899SCharles.Forsyth return 1; 443*37da2899SCharles.Forsyth} 444*37da2899SCharles.Forsyth 445*37da2899SCharles.Forsythmustscavenge(a : ref Ftl) : int 446*37da2899SCharles.Forsyth{ 447*37da2899SCharles.Forsyth return a.needspace || a.detach == Deferred; 448*37da2899SCharles.Forsyth} 449*37da2899SCharles.Forsyth 450*37da2899SCharles.Forsythdonescavenge(a : ref Ftl) : int 451*37da2899SCharles.Forsyth{ 452*37da2899SCharles.Forsyth return a.needspace == 0; 453*37da2899SCharles.Forsyth} 454*37da2899SCharles.Forsyth 455*37da2899SCharles.Forsythscavengeproc(arg : ref Ftl) 456*37da2899SCharles.Forsyth{ 457*37da2899SCharles.Forsyth ftl : ref Ftl; 458*37da2899SCharles.Forsyth i : int; 459*37da2899SCharles.Forsyth e, ne : ref Terase; 460*37da2899SCharles.Forsyth 461*37da2899SCharles.Forsyth ftl = arg; 462*37da2899SCharles.Forsyth if(mustscavenge(ftl)){ 463*37da2899SCharles.Forsyth if(ftl.detach == Deferred){ 464*37da2899SCharles.Forsyth ftlfree(ftl); 465*37da2899SCharles.Forsyth fprint(stderr, "scavenge out of memory\n"); 466*37da2899SCharles.Forsyth exit; 467*37da2899SCharles.Forsyth } 468*37da2899SCharles.Forsyth if(FTLDEBUG || ftl.trace || trace) 469*37da2899SCharles.Forsyth print("ftl: scavenge %d\n", ftl.nfree); 470*37da2899SCharles.Forsyth e = bestcopy(ftl); 471*37da2899SCharles.Forsyth if(e == nil || ftl.xfer < 0 || (ne = ftl.unit[ftl.xfer]) == nil || ne.id != XferID || e == ne) 472*37da2899SCharles.Forsyth ; 473*37da2899SCharles.Forsyth else if(copyunit(ftl, e, ne)){ 474*37da2899SCharles.Forsyth i = ne.x; ne.x = e.x; e.x = i; 475*37da2899SCharles.Forsyth ftl.unit[ne.x] = ne; 476*37da2899SCharles.Forsyth ftl.unit[e.x] = e; 477*37da2899SCharles.Forsyth ftl.xfer = e.x; 478*37da2899SCharles.Forsyth e.id = XferID; 479*37da2899SCharles.Forsyth e.nbam = 0; 480*37da2899SCharles.Forsyth e.bam = nil; 481*37da2899SCharles.Forsyth e.bamx = 0; 482*37da2899SCharles.Forsyth e.nerase++; 483*37da2899SCharles.Forsyth eraseinit(ftl, e.offset, XferID, e.nerase); 484*37da2899SCharles.Forsyth } 485*37da2899SCharles.Forsyth if(FTLDEBUG || ftl.trace || trace) 486*37da2899SCharles.Forsyth print("ftl: end scavenge %d\n", ftl.nfree); 487*37da2899SCharles.Forsyth ftl.needspace = 0; 488*37da2899SCharles.Forsyth } 489*37da2899SCharles.Forsyth} 490*37da2899SCharles.Forsyth 491*37da2899SCharles.Forsythscavenge(ftl : ref Ftl) : int 492*37da2899SCharles.Forsyth{ 493*37da2899SCharles.Forsyth if(ftl.xfer < 0 || bestcopy(ftl) == nil) 494*37da2899SCharles.Forsyth return 0; # you worm! 495*37da2899SCharles.Forsyth 496*37da2899SCharles.Forsyth if(!ftl.hasproc){ 497*37da2899SCharles.Forsyth ftl.hasproc = 1; 498*37da2899SCharles.Forsyth } 499*37da2899SCharles.Forsyth ftl.needspace = 1; 500*37da2899SCharles.Forsyth 501*37da2899SCharles.Forsyth scavengeproc(ftls); 502*37da2899SCharles.Forsyth 503*37da2899SCharles.Forsyth return ftl.nfree; 504*37da2899SCharles.Forsyth} 505*37da2899SCharles.Forsyth 506*37da2899SCharles.Forsythputbam(ftl : ref Ftl, e : ref Terase, n : int, entry : int) 507*37da2899SCharles.Forsyth{ 508*37da2899SCharles.Forsyth b := array[4] of byte; 509*37da2899SCharles.Forsyth 510*37da2899SCharles.Forsyth PUT4(e.bam[4*n:], entry); 511*37da2899SCharles.Forsyth PUT4(b, entry); 512*37da2899SCharles.Forsyth putflash(ftl, e.bamoffset + n*4, b, 4); 513*37da2899SCharles.Forsyth} 514*37da2899SCharles.Forsyth 515*37da2899SCharles.Forsythallocblk(ftl : ref Ftl) : int 516*37da2899SCharles.Forsyth{ 517*37da2899SCharles.Forsyth e : ref Terase; 518*37da2899SCharles.Forsyth i, j : int; 519*37da2899SCharles.Forsyth 520*37da2899SCharles.Forsyth i = ftl.lastx; 521*37da2899SCharles.Forsyth do{ 522*37da2899SCharles.Forsyth e = ftl.unit[i]; 523*37da2899SCharles.Forsyth if(e != nil && e.id != XferID && e.nfree){ 524*37da2899SCharles.Forsyth ftl.lastx = i; 525*37da2899SCharles.Forsyth for(j=e.bamx; j<e.nbam; j++) 526*37da2899SCharles.Forsyth if(GET4(e.bam[4*j:])== Bfree){ 527*37da2899SCharles.Forsyth putbam(ftl, e, j, Bwriting); 528*37da2899SCharles.Forsyth ftl.nfree--; 529*37da2899SCharles.Forsyth e.nfree--; 530*37da2899SCharles.Forsyth e.bamx = j+1; 531*37da2899SCharles.Forsyth return (e.x<<16) | j; 532*37da2899SCharles.Forsyth } 533*37da2899SCharles.Forsyth e.nfree = 0; 534*37da2899SCharles.Forsyth print("ftl: unit %d:#%x nfree %d but not free in BAM\n", e.x, e.id, e.nfree); 535*37da2899SCharles.Forsyth } 536*37da2899SCharles.Forsyth if(++i >= ftl.nunit) 537*37da2899SCharles.Forsyth i = 0; 538*37da2899SCharles.Forsyth }while(i != ftl.lastx); 539*37da2899SCharles.Forsyth return 0; 540*37da2899SCharles.Forsyth} 541*37da2899SCharles.Forsyth 542*37da2899SCharles.Forsythmapblk(ftl : ref Ftl, bno : int) : (int, ref Terase, int) 543*37da2899SCharles.Forsyth{ 544*37da2899SCharles.Forsyth v : int; 545*37da2899SCharles.Forsyth x : int; 546*37da2899SCharles.Forsyth 547*37da2899SCharles.Forsyth if(bno < ftl.nblock){ 548*37da2899SCharles.Forsyth v = ftl.vbm[bno]; 549*37da2899SCharles.Forsyth if(v == 0 || v == ~0) 550*37da2899SCharles.Forsyth return (0, nil, 0); 551*37da2899SCharles.Forsyth x = v>>16; 552*37da2899SCharles.Forsyth if(x >= ftl.nunit || x == ftl.xfer || ftl.unit[x] == nil){ 553*37da2899SCharles.Forsyth print("ftl: corrupt format: bad block mapping %d . unit #%x\n", bno, x); 554*37da2899SCharles.Forsyth return (0, nil, 0); 555*37da2899SCharles.Forsyth } 556*37da2899SCharles.Forsyth return (1, ftl.unit[x], v & 16rFFFF); 557*37da2899SCharles.Forsyth } 558*37da2899SCharles.Forsyth return (0, nil, 0); 559*37da2899SCharles.Forsyth} 560*37da2899SCharles.Forsyth 561*37da2899SCharles.Forsytheraseinit(ftl : ref Ftl, offset : int, id : int, nerase : int) 562*37da2899SCharles.Forsyth{ 563*37da2899SCharles.Forsyth m : array of byte; 564*37da2899SCharles.Forsyth bam : array of byte; 565*37da2899SCharles.Forsyth i, nov : int; 566*37da2899SCharles.Forsyth 567*37da2899SCharles.Forsyth nov = ((ftl.segsize/Bsize)*4 + BAMoffset + Bsize - 1)/Bsize; # number of overhead blocks (header, and BAM itself) 568*37da2899SCharles.Forsyth if(nov*Bsize >= ftl.segsize) { 569*37da2899SCharles.Forsyth fprint(stderr, "ftl -- too small for files"); 570*37da2899SCharles.Forsyth exit; 571*37da2899SCharles.Forsyth } 572*37da2899SCharles.Forsyth eraseflash(ftl, offset); 573*37da2899SCharles.Forsyth m = array[ERASEHDRLEN] of byte; 574*37da2899SCharles.Forsyth if(m == nil) { 575*37da2899SCharles.Forsyth fprint(stderr, "nomem\n"); 576*37da2899SCharles.Forsyth exit; 577*37da2899SCharles.Forsyth } 578*37da2899SCharles.Forsyth memset(m, 16rFF, len m); 579*37da2899SCharles.Forsyth m[O_LINKTUPLE+0] = byte 16r13; 580*37da2899SCharles.Forsyth m[O_LINKTUPLE+1] = byte 16r3; 581*37da2899SCharles.Forsyth memmove(m[O_LINKTUPLE+2:], array of byte "CIS", 3); 582*37da2899SCharles.Forsyth m[O_ORGTUPLE+0] = byte 16r46; 583*37da2899SCharles.Forsyth m[O_ORGTUPLE+1] = byte 16r57; 584*37da2899SCharles.Forsyth m[O_ORGTUPLE+2] = byte 16r00; 585*37da2899SCharles.Forsyth memmove(m[O_ORGTUPLE+3:], array of byte "FTL100\0", 7); 586*37da2899SCharles.Forsyth m[O_NXFER] = byte 1; 587*37da2899SCharles.Forsyth PUT4(m[O_NERASE:], nerase); 588*37da2899SCharles.Forsyth PUT2(m[O_ID:], id); 589*37da2899SCharles.Forsyth m[O_BSHIFT] = byte ftl.bshift; 590*37da2899SCharles.Forsyth m[O_ESHIFT] = byte ftl.eshift; 591*37da2899SCharles.Forsyth PUT2(m[O_PSTART:], 0); 592*37da2899SCharles.Forsyth PUT2(m[O_NUNITS:], ftl.nunit); 593*37da2899SCharles.Forsyth PUT4(m[O_PSIZE:], ftl.size - nov*Bsize); 594*37da2899SCharles.Forsyth PUT4(m[O_VBMBASE:], -1); # we always calculate the VBM (16rffffffff) 595*37da2899SCharles.Forsyth PUT2(m[O_NVBM:], 0); 596*37da2899SCharles.Forsyth m[O_FLAGS] = byte 0; 597*37da2899SCharles.Forsyth m[O_CODE] = byte 16rFF; 598*37da2899SCharles.Forsyth memmove(m[O_SERIAL:], array of byte "Inf1", 4); 599*37da2899SCharles.Forsyth PUT4(m[O_ALTOFFSET:], 0); 600*37da2899SCharles.Forsyth PUT4(m[O_BAMOFFSET:], BAMoffset); 601*37da2899SCharles.Forsyth putflash(ftl, offset, m, ERASEHDRLEN); 602*37da2899SCharles.Forsyth m = nil; 603*37da2899SCharles.Forsyth if(id == XferID) 604*37da2899SCharles.Forsyth return; 605*37da2899SCharles.Forsyth nov *= 4; # now bytes of BAM 606*37da2899SCharles.Forsyth bam = array[nov] of byte; 607*37da2899SCharles.Forsyth if(bam == nil) { 608*37da2899SCharles.Forsyth fprint(stderr, "nomem"); 609*37da2899SCharles.Forsyth exit; 610*37da2899SCharles.Forsyth } 611*37da2899SCharles.Forsyth for(i=0; i<nov; i += 4) 612*37da2899SCharles.Forsyth PUT4(bam[i:], ControlBlock); # reserve them 613*37da2899SCharles.Forsyth putflash(ftl, offset+BAMoffset, bam, nov); 614*37da2899SCharles.Forsyth bam = nil; 615*37da2899SCharles.Forsyth} 616*37da2899SCharles.Forsyth 617*37da2899SCharles.Forsytheraseload(ftl : ref Ftl, x : int, offset : int) : ref Terase 618*37da2899SCharles.Forsyth{ 619*37da2899SCharles.Forsyth m : array of byte; 620*37da2899SCharles.Forsyth e : ref Terase; 621*37da2899SCharles.Forsyth i, nbam : int; 622*37da2899SCharles.Forsyth bno, v : int; 623*37da2899SCharles.Forsyth 624*37da2899SCharles.Forsyth m = array[ERASEHDRLEN] of byte; 625*37da2899SCharles.Forsyth if(m == nil) { 626*37da2899SCharles.Forsyth fprint(stderr, "nomem"); 627*37da2899SCharles.Forsyth exit; 628*37da2899SCharles.Forsyth } 629*37da2899SCharles.Forsyth getflash(ftl, m, offset, ERASEHDRLEN); 630*37da2899SCharles.Forsyth if(memcmp(m[O_ORGTUPLE+3:], array of byte "FTL100\0", 7) != 0 || 631*37da2899SCharles.Forsyth memcmp(m[O_SERIAL:], array of byte "Inf1", 4) != 0){ 632*37da2899SCharles.Forsyth m = nil; 633*37da2899SCharles.Forsyth return nil; 634*37da2899SCharles.Forsyth } 635*37da2899SCharles.Forsyth e = ref Terase; 636*37da2899SCharles.Forsyth if(e == nil){ 637*37da2899SCharles.Forsyth m = nil; 638*37da2899SCharles.Forsyth fprint(stderr, "nomem"); 639*37da2899SCharles.Forsyth exit; 640*37da2899SCharles.Forsyth } 641*37da2899SCharles.Forsyth e.x = x; 642*37da2899SCharles.Forsyth e.id = GET2(m[O_ID:]); 643*37da2899SCharles.Forsyth e.offset = offset; 644*37da2899SCharles.Forsyth e.bamoffset = GET4(m[O_BAMOFFSET:]); 645*37da2899SCharles.Forsyth e.nerase = GET4(m[O_NERASE:]); 646*37da2899SCharles.Forsyth e.bamx = 0; 647*37da2899SCharles.Forsyth e.nfree = 0; 648*37da2899SCharles.Forsyth e.nused = 0; 649*37da2899SCharles.Forsyth e.ndead = 0; 650*37da2899SCharles.Forsyth e.nbad = 0; 651*37da2899SCharles.Forsyth m = nil; 652*37da2899SCharles.Forsyth if(e.bamoffset != BAMoffset){ 653*37da2899SCharles.Forsyth e = nil; 654*37da2899SCharles.Forsyth return nil; 655*37da2899SCharles.Forsyth } 656*37da2899SCharles.Forsyth e.bamoffset += offset; 657*37da2899SCharles.Forsyth if(e.id == XferID || e.id == XferBusy){ 658*37da2899SCharles.Forsyth e.bam = nil; 659*37da2899SCharles.Forsyth e.nbam = 0; 660*37da2899SCharles.Forsyth return e; 661*37da2899SCharles.Forsyth } 662*37da2899SCharles.Forsyth nbam = ftl.segsize/Bsize; 663*37da2899SCharles.Forsyth e.bam = array[4*nbam] of byte; 664*37da2899SCharles.Forsyth e.nbam = nbam; 665*37da2899SCharles.Forsyth getflash(ftl, e.bam, e.bamoffset, nbam*4); 666*37da2899SCharles.Forsyth # scan BAM to build VBM 667*37da2899SCharles.Forsyth e.bamx = 0; 668*37da2899SCharles.Forsyth for(i=0; i<nbam; i++){ 669*37da2899SCharles.Forsyth v = GET4(e.bam[4*i:]); 670*37da2899SCharles.Forsyth if(v == Bwriting || v == Bdeleted) 671*37da2899SCharles.Forsyth e.ndead++; 672*37da2899SCharles.Forsyth else if(v == Bfree){ 673*37da2899SCharles.Forsyth if(e.bamx == 0) 674*37da2899SCharles.Forsyth e.bamx = i; 675*37da2899SCharles.Forsyth e.nfree++; 676*37da2899SCharles.Forsyth ftl.nfree++; 677*37da2899SCharles.Forsyth }else{ 678*37da2899SCharles.Forsyth case(v & BlockType){ 679*37da2899SCharles.Forsyth ControlBlock => 680*37da2899SCharles.Forsyth break; 681*37da2899SCharles.Forsyth DataBlock => 682*37da2899SCharles.Forsyth # add to VBM 683*37da2899SCharles.Forsyth if(v & (1<<31)) 684*37da2899SCharles.Forsyth break; # negative => VBM page, ignored 685*37da2899SCharles.Forsyth bno = BNO(v & ~BlockType); 686*37da2899SCharles.Forsyth if(i < ftl.fstart || bno >= ftl.nblock){ 687*37da2899SCharles.Forsyth print("ftl: unit %d:#%x bad bam[%d]=#%x\n", e.x, e.id, i, v); 688*37da2899SCharles.Forsyth e.nbad++; 689*37da2899SCharles.Forsyth break; 690*37da2899SCharles.Forsyth } 691*37da2899SCharles.Forsyth ftl.vbm[bno] = (e.x<<16) | i; 692*37da2899SCharles.Forsyth e.nused++; 693*37da2899SCharles.Forsyth break; 694*37da2899SCharles.Forsyth ReplacePage => 695*37da2899SCharles.Forsyth # replacement VBM page; ignored 696*37da2899SCharles.Forsyth break; 697*37da2899SCharles.Forsyth BadBlock => 698*37da2899SCharles.Forsyth e.nbad++; 699*37da2899SCharles.Forsyth break; 700*37da2899SCharles.Forsyth * => 701*37da2899SCharles.Forsyth print("ftl: unit %d:#%x bad bam[%d]=%x\n", e.x, e.id, i, v); 702*37da2899SCharles.Forsyth } 703*37da2899SCharles.Forsyth } 704*37da2899SCharles.Forsyth } 705*37da2899SCharles.Forsyth return e; 706*37da2899SCharles.Forsyth} 707*37da2899SCharles.Forsyth 708*37da2899SCharles.Forsytherasefree(e : ref Terase) 709*37da2899SCharles.Forsyth{ 710*37da2899SCharles.Forsyth e.bam = nil; 711*37da2899SCharles.Forsyth e = nil; 712*37da2899SCharles.Forsyth} 713*37da2899SCharles.Forsyth 714*37da2899SCharles.Forsytheraseflash(ftl : ref Ftl, offset : int) 715*37da2899SCharles.Forsyth{ 716*37da2899SCharles.Forsyth offset += ftl.base; 717*37da2899SCharles.Forsyth if(FTLDEBUG || ftl.trace || trace) 718*37da2899SCharles.Forsyth print("ftl: erase seg @#%x\n", offset); 719*37da2899SCharles.Forsyth memset(flashm[offset:], 16rff, secsize); 720*37da2899SCharles.Forsyth} 721*37da2899SCharles.Forsyth 722*37da2899SCharles.Forsythputflash(ftl : ref Ftl, offset : int, buf : array of byte, n : int) 723*37da2899SCharles.Forsyth{ 724*37da2899SCharles.Forsyth offset += ftl.base; 725*37da2899SCharles.Forsyth if(ftl.trace || trace) 726*37da2899SCharles.Forsyth print("ftl: write(#%x, %d)\n", offset, n); 727*37da2899SCharles.Forsyth memmove(flashm[offset:], buf, n); 728*37da2899SCharles.Forsyth} 729*37da2899SCharles.Forsyth 730*37da2899SCharles.Forsythgetflash(ftl : ref Ftl, buf : array of byte, offset : int, n : int) 731*37da2899SCharles.Forsyth{ 732*37da2899SCharles.Forsyth offset += ftl.base; 733*37da2899SCharles.Forsyth if(ftl.trace || trace) 734*37da2899SCharles.Forsyth print("ftl: read(#%x, %d)\n", offset, n); 735*37da2899SCharles.Forsyth memmove(buf, flashm[offset:], n); 736*37da2899SCharles.Forsyth} 737*37da2899SCharles.Forsyth 738*37da2899SCharles.ForsythBUFSIZE : con 8192; 739*37da2899SCharles.Forsyth 740*37da2899SCharles.Forsythmain(argv : list of string) 741*37da2899SCharles.Forsyth{ 742*37da2899SCharles.Forsyth k, r, sz, offset : int = 0; 743*37da2899SCharles.Forsyth buf, buf1 : array of byte; 744*37da2899SCharles.Forsyth fd1, fd2 : ref FD; 745*37da2899SCharles.Forsyth 746*37da2899SCharles.Forsyth if (len argv != 5) { 747*37da2899SCharles.Forsyth fprint(stderr, "usage: %s flashsize secsize kfsfile flashfile\n", hd argv); 748*37da2899SCharles.Forsyth exit; 749*37da2899SCharles.Forsyth } 750*37da2899SCharles.Forsyth flashsize = atoi(hd tl argv); 751*37da2899SCharles.Forsyth secsize = atoi(hd tl tl argv); 752*37da2899SCharles.Forsyth fd1 = open(hd tl tl tl argv, OREAD); 753*37da2899SCharles.Forsyth fd2 = create(hd tl tl tl tl argv, OWRITE, 8r644); 754*37da2899SCharles.Forsyth if (fd1 == nil || fd2 == nil) { 755*37da2899SCharles.Forsyth fprint(stderr, "bad io files\n"); 756*37da2899SCharles.Forsyth exit; 757*37da2899SCharles.Forsyth } 758*37da2899SCharles.Forsyth if(secsize == 0 || secsize > flashsize || secsize&(secsize-1) || 0&(secsize-1) || flashsize == 0 || flashsize != Nolimit && flashsize&(secsize-1)) { 759*37da2899SCharles.Forsyth fprint(stderr, "ftl: bad sizes\n"); 760*37da2899SCharles.Forsyth exit; 761*37da2899SCharles.Forsyth } 762*37da2899SCharles.Forsyth for(k=0; k<32 && (1<<k) != secsize; k++) 763*37da2899SCharles.Forsyth ; 764*37da2899SCharles.Forsyth flashm = array[flashsize] of byte; 765*37da2899SCharles.Forsyth buf = array[BUFSIZE] of byte; 766*37da2899SCharles.Forsyth if (flashm == nil) { 767*37da2899SCharles.Forsyth fprint(stderr, "ftl: no mem for flash\n"); 768*37da2899SCharles.Forsyth exit; 769*37da2899SCharles.Forsyth } 770*37da2899SCharles.Forsyth ftls = mkftl("FLASH", 0, Nolimit, k, "format"); 771*37da2899SCharles.Forsyth for (;;) { 772*37da2899SCharles.Forsyth r = read(fd1, buf, BUFSIZE); 773*37da2899SCharles.Forsyth if (r <= 0) 774*37da2899SCharles.Forsyth break; 775*37da2899SCharles.Forsyth if (ftlwrite(buf, r, offset) != r) { 776*37da2899SCharles.Forsyth fprint(stderr, "ftl: ftlwrite failed - input file too big\n"); 777*37da2899SCharles.Forsyth exit; 778*37da2899SCharles.Forsyth } 779*37da2899SCharles.Forsyth offset += r; 780*37da2899SCharles.Forsyth } 781*37da2899SCharles.Forsyth write(fd2, flashm, flashsize); 782*37da2899SCharles.Forsyth fd1 = fd2 = nil; 783*37da2899SCharles.Forsyth ftlstat(offset); 784*37da2899SCharles.Forsyth # ftls = mkftl("FLASH", 0, Nolimit, k, "init"); 785*37da2899SCharles.Forsyth sz = offset; 786*37da2899SCharles.Forsyth offset = 0; 787*37da2899SCharles.Forsyth buf1 = array[BUFSIZE] of byte; 788*37da2899SCharles.Forsyth fd1 = open(hd tl tl tl argv, OREAD); 789*37da2899SCharles.Forsyth for (;;) { 790*37da2899SCharles.Forsyth r = read(fd1, buf1, BUFSIZE); 791*37da2899SCharles.Forsyth if (r <= 0) 792*37da2899SCharles.Forsyth break; 793*37da2899SCharles.Forsyth if (ftlread(buf, r, offset) != r) { 794*37da2899SCharles.Forsyth fprint(stderr, "ftl: ftlread failed\n"); 795*37da2899SCharles.Forsyth exit; 796*37da2899SCharles.Forsyth } 797*37da2899SCharles.Forsyth if (memcmp(buf, buf1, r) != 0) { 798*37da2899SCharles.Forsyth fprint(stderr, "ftl: bad read\n"); 799*37da2899SCharles.Forsyth exit; 800*37da2899SCharles.Forsyth } 801*37da2899SCharles.Forsyth offset += r; 802*37da2899SCharles.Forsyth } 803*37da2899SCharles.Forsyth fd1 = nil; 804*37da2899SCharles.Forsyth if (offset != sz) { 805*37da2899SCharles.Forsyth fprint(stderr, "ftl: bad final offset\n"); 806*37da2899SCharles.Forsyth exit; 807*37da2899SCharles.Forsyth } 808*37da2899SCharles.Forsyth exit; 809*37da2899SCharles.Forsyth} 810*37da2899SCharles.Forsyth 811*37da2899SCharles.Forsythinit(nil : ref Draw->Context, argl : list of string) 812*37da2899SCharles.Forsyth{ 813*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 814*37da2899SCharles.Forsyth stderr = sys->fildes(2); 815*37da2899SCharles.Forsyth main(argl); 816*37da2899SCharles.Forsyth} 817*37da2899SCharles.Forsyth 818*37da2899SCharles.Forsythmemset(d : array of byte, v : int, n : int) 819*37da2899SCharles.Forsyth{ 820*37da2899SCharles.Forsyth for (i := 0; i < n; i++) 821*37da2899SCharles.Forsyth d[i] = byte v; 822*37da2899SCharles.Forsyth} 823*37da2899SCharles.Forsyth 824*37da2899SCharles.Forsythmemmove(d : array of byte, s : array of byte, n : int) 825*37da2899SCharles.Forsyth{ 826*37da2899SCharles.Forsyth d[0:] = s[0:n]; 827*37da2899SCharles.Forsyth} 828*37da2899SCharles.Forsyth 829*37da2899SCharles.Forsythmemcmp(s1 : array of byte, s2 : array of byte, n : int) : int 830*37da2899SCharles.Forsyth{ 831*37da2899SCharles.Forsyth for (i := 0; i < n; i++) { 832*37da2899SCharles.Forsyth if (s1[i] < s2[i]) 833*37da2899SCharles.Forsyth return -1; 834*37da2899SCharles.Forsyth if (s1[i] > s2[i]) 835*37da2899SCharles.Forsyth return 1; 836*37da2899SCharles.Forsyth } 837*37da2899SCharles.Forsyth return 0; 838*37da2899SCharles.Forsyth} 839*37da2899SCharles.Forsyth 840*37da2899SCharles.Forsythatoi(s : string) : int 841*37da2899SCharles.Forsyth{ 842*37da2899SCharles.Forsyth v : int; 843*37da2899SCharles.Forsyth base := 10; 844*37da2899SCharles.Forsyth n := len s; 845*37da2899SCharles.Forsyth neg := 0; 846*37da2899SCharles.Forsyth 847*37da2899SCharles.Forsyth for (i := 0; i < n && (s[i] == ' ' || s[i] == '\t'); i++) 848*37da2899SCharles.Forsyth ; 849*37da2899SCharles.Forsyth if (s[i] == '+' || s[i] == '-') { 850*37da2899SCharles.Forsyth if (s[i] == '-') 851*37da2899SCharles.Forsyth neg = 1; 852*37da2899SCharles.Forsyth i++; 853*37da2899SCharles.Forsyth } 854*37da2899SCharles.Forsyth if (n-i >= 2 && s[i] == '0' && s[i+1] == 'x') { 855*37da2899SCharles.Forsyth base = 16; 856*37da2899SCharles.Forsyth i += 2; 857*37da2899SCharles.Forsyth } 858*37da2899SCharles.Forsyth else if (n-i >= 1 && s[i] == '0') { 859*37da2899SCharles.Forsyth base = 8; 860*37da2899SCharles.Forsyth i++; 861*37da2899SCharles.Forsyth } 862*37da2899SCharles.Forsyth m := 0; 863*37da2899SCharles.Forsyth for(; i < n; i++) { 864*37da2899SCharles.Forsyth c := s[i]; 865*37da2899SCharles.Forsyth case c { 866*37da2899SCharles.Forsyth 'a' to 'z' => 867*37da2899SCharles.Forsyth v = c - 'a' + 10; 868*37da2899SCharles.Forsyth 'A' to 'Z' => 869*37da2899SCharles.Forsyth v = c - 'A' + 10; 870*37da2899SCharles.Forsyth '0' to '9' => 871*37da2899SCharles.Forsyth v = c - '0'; 872*37da2899SCharles.Forsyth * => 873*37da2899SCharles.Forsyth fprint(stderr, "ftl: bad character in number %s\n", s); 874*37da2899SCharles.Forsyth exit; 875*37da2899SCharles.Forsyth } 876*37da2899SCharles.Forsyth if(v >= base) { 877*37da2899SCharles.Forsyth fprint(stderr, "ftl: character too big for base in %s\n", s); 878*37da2899SCharles.Forsyth exit; 879*37da2899SCharles.Forsyth } 880*37da2899SCharles.Forsyth m = m * base + v; 881*37da2899SCharles.Forsyth } 882*37da2899SCharles.Forsyth if(neg) 883*37da2899SCharles.Forsyth m = -m; 884*37da2899SCharles.Forsyth return m; 885*37da2899SCharles.Forsyth} 886*37da2899SCharles.Forsyth 887*37da2899SCharles.Forsyth# little endian 888*37da2899SCharles.Forsyth 889*37da2899SCharles.ForsythGET2(b : array of byte) : int 890*37da2899SCharles.Forsyth{ 891*37da2899SCharles.Forsyth return ((int b[1]) << 8) | (int b[0]); 892*37da2899SCharles.Forsyth} 893*37da2899SCharles.Forsyth 894*37da2899SCharles.ForsythGET4(b : array of byte) : int 895*37da2899SCharles.Forsyth{ 896*37da2899SCharles.Forsyth return ((int b[3]) << 24) | ((int b[2]) << 16) | ((int b[1]) << 8) | (int b[0]); 897*37da2899SCharles.Forsyth} 898*37da2899SCharles.Forsyth 899*37da2899SCharles.ForsythPUT2(b : array of byte, v : int) 900*37da2899SCharles.Forsyth{ 901*37da2899SCharles.Forsyth b[1] = byte (v>>8); 902*37da2899SCharles.Forsyth b[0] = byte v; 903*37da2899SCharles.Forsyth} 904*37da2899SCharles.Forsyth 905*37da2899SCharles.ForsythPUT4(b : array of byte, v : int) 906*37da2899SCharles.Forsyth{ 907*37da2899SCharles.Forsyth b[3] = byte (v>>24); 908*37da2899SCharles.Forsyth b[2] = byte (v>>16); 909*37da2899SCharles.Forsyth b[1] = byte (v>>8); 910*37da2899SCharles.Forsyth b[0] = byte v; 911*37da2899SCharles.Forsyth} 912