ftest.py 293 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220
  1. # SPDX-License-Identifier: GPL-2.0+
  2. # Copyright (c) 2016 Google, Inc
  3. # Written by Simon Glass <sjg@chromium.org>
  4. #
  5. # To run a single test, change to this directory, and:
  6. #
  7. # python -m unittest func_test.TestFunctional.testHelp
  8. import collections
  9. import gzip
  10. import hashlib
  11. from optparse import OptionParser
  12. import os
  13. import re
  14. import shutil
  15. import struct
  16. import sys
  17. import tempfile
  18. import unittest
  19. import unittest.mock
  20. import urllib.error
  21. from binman import bintool
  22. from binman import cbfs_util
  23. from binman import cmdline
  24. from binman import control
  25. from binman import elf
  26. from binman import elf_test
  27. from binman import fip_util
  28. from binman import fmap_util
  29. from binman import state
  30. from dtoc import fdt
  31. from dtoc import fdt_util
  32. from binman.etype import fdtmap
  33. from binman.etype import image_header
  34. from binman.image import Image
  35. from u_boot_pylib import command
  36. from u_boot_pylib import test_util
  37. from u_boot_pylib import tools
  38. from u_boot_pylib import tout
  39. # Contents of test files, corresponding to different entry types
  40. U_BOOT_DATA = b'1234'
  41. U_BOOT_IMG_DATA = b'img'
  42. U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
  43. U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
  44. U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
  45. BLOB_DATA = b'89'
  46. ME_DATA = b'0abcd'
  47. VGA_DATA = b'vga'
  48. U_BOOT_DTB_DATA = b'udtb'
  49. U_BOOT_SPL_DTB_DATA = b'spldtb'
  50. U_BOOT_TPL_DTB_DATA = b'tpldtb'
  51. U_BOOT_VPL_DTB_DATA = b'vpldtb'
  52. X86_START16_DATA = b'start16'
  53. X86_START16_SPL_DATA = b'start16spl'
  54. X86_START16_TPL_DATA = b'start16tpl'
  55. X86_RESET16_DATA = b'reset16'
  56. X86_RESET16_SPL_DATA = b'reset16spl'
  57. X86_RESET16_TPL_DATA = b'reset16tpl'
  58. PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
  59. U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
  60. U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
  61. U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
  62. U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
  63. U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
  64. U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
  65. U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
  66. FSP_DATA = b'fsp'
  67. CMC_DATA = b'cmc'
  68. VBT_DATA = b'vbt'
  69. MRC_DATA = b'mrc'
  70. TEXT_DATA = 'text'
  71. TEXT_DATA2 = 'text2'
  72. TEXT_DATA3 = 'text3'
  73. CROS_EC_RW_DATA = b'ecrw'
  74. GBB_DATA = b'gbbd'
  75. BMPBLK_DATA = b'bmp'
  76. VBLOCK_DATA = b'vblk'
  77. FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
  78. b"sorry you're alive\n")
  79. COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
  80. COMPRESS_DATA_BIG = COMPRESS_DATA * 2
  81. REFCODE_DATA = b'refcode'
  82. FSP_M_DATA = b'fsp_m'
  83. FSP_S_DATA = b'fsp_s'
  84. FSP_T_DATA = b'fsp_t'
  85. ATF_BL31_DATA = b'bl31'
  86. TEE_OS_DATA = b'this is some tee OS data'
  87. ATF_BL2U_DATA = b'bl2u'
  88. OPENSBI_DATA = b'opensbi'
  89. SCP_DATA = b'scp'
  90. ROCKCHIP_TPL_DATA = b'rockchip-tpl'
  91. TEST_FDT1_DATA = b'fdt1'
  92. TEST_FDT2_DATA = b'test-fdt2'
  93. ENV_DATA = b'var1=1\nvar2="2"'
  94. ENCRYPTED_IV_DATA = b'123456'
  95. ENCRYPTED_KEY_DATA = b'abcde'
  96. PRE_LOAD_MAGIC = b'UBSH'
  97. PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
  98. PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
  99. TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  100. TI_UNSECURE_DATA = b'unsecuredata'
  101. # Subdirectory of the input dir to use to put test FDTs
  102. TEST_FDT_SUBDIR = 'fdts'
  103. # The expected size for the device tree in some tests
  104. EXTRACT_DTB_SIZE = 0x3c9
  105. # Properties expected to be in the device tree when update_dtb is used
  106. BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
  107. # Extra properties expected to be in the device tree when allow-repack is used
  108. REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
  109. # Supported compression bintools
  110. COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
  111. TEE_ADDR = 0x5678
  112. class TestFunctional(unittest.TestCase):
  113. """Functional tests for binman
  114. Most of these use a sample .dts file to build an image and then check
  115. that it looks correct. The sample files are in the test/ subdirectory
  116. and are numbered.
  117. For each entry type a very small test file is created using fixed
  118. string contents. This makes it easy to test that things look right, and
  119. debug problems.
  120. In some cases a 'real' file must be used - these are also supplied in
  121. the test/ diurectory.
  122. """
  123. @classmethod
  124. def setUpClass(cls):
  125. global entry
  126. from binman import entry
  127. # Handle the case where argv[0] is 'python'
  128. cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
  129. cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
  130. # Create a temporary directory for input files
  131. cls._indir = tempfile.mkdtemp(prefix='binmant.')
  132. # Create some test files
  133. TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
  134. TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
  135. TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
  136. TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
  137. TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
  138. TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
  139. TestFunctional._MakeInputFile('me.bin', ME_DATA)
  140. TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
  141. cls._ResetDtbs()
  142. TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
  143. TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
  144. TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
  145. X86_START16_SPL_DATA)
  146. TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
  147. X86_START16_TPL_DATA)
  148. TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
  149. X86_RESET16_DATA)
  150. TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
  151. X86_RESET16_SPL_DATA)
  152. TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
  153. X86_RESET16_TPL_DATA)
  154. TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
  155. TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
  156. U_BOOT_SPL_NODTB_DATA)
  157. TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
  158. U_BOOT_TPL_NODTB_DATA)
  159. TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
  160. U_BOOT_VPL_NODTB_DATA)
  161. TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
  162. TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
  163. TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
  164. TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
  165. TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
  166. TestFunctional._MakeInputDir('devkeys')
  167. TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
  168. TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
  169. TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
  170. TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
  171. TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
  172. cls._elf_testdir = os.path.join(cls._indir, 'elftest')
  173. elf_test.BuildElfTestFiles(cls._elf_testdir)
  174. # ELF file with a '_dt_ucode_base_size' symbol
  175. TestFunctional._MakeInputFile('u-boot',
  176. tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
  177. # Intel flash descriptor file
  178. cls._SetupDescriptor()
  179. shutil.copytree(cls.TestFile('files'),
  180. os.path.join(cls._indir, 'files'))
  181. shutil.copytree(cls.TestFile('yaml'),
  182. os.path.join(cls._indir, 'yaml'))
  183. TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
  184. TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
  185. TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
  186. TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
  187. TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
  188. TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
  189. TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
  190. TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
  191. TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
  192. # Add a few .dtb files for testing
  193. TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
  194. TEST_FDT1_DATA)
  195. TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
  196. TEST_FDT2_DATA)
  197. TestFunctional._MakeInputFile('env.txt', ENV_DATA)
  198. # ELF file with two sections in different parts of memory, used for both
  199. # ATF and OP_TEE
  200. TestFunctional._MakeInputFile('bl31.elf',
  201. tools.read_file(cls.ElfTestFile('elf_sections')))
  202. TestFunctional._MakeInputFile('tee.elf',
  203. tools.read_file(cls.ElfTestFile('elf_sections')))
  204. # Newer OP_TEE file in v1 binary format
  205. cls.make_tee_bin('tee.bin')
  206. # test files for encrypted tests
  207. TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
  208. TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
  209. cls.comp_bintools = {}
  210. for name in COMP_BINTOOLS:
  211. cls.comp_bintools[name] = bintool.Bintool.create(name)
  212. @classmethod
  213. def tearDownClass(cls):
  214. """Remove the temporary input directory and its contents"""
  215. if cls.preserve_indir:
  216. print('Preserving input dir: %s' % cls._indir)
  217. else:
  218. if cls._indir:
  219. shutil.rmtree(cls._indir)
  220. cls._indir = None
  221. @classmethod
  222. def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
  223. toolpath=None, verbosity=None):
  224. """Accept arguments controlling test execution
  225. Args:
  226. preserve_indir: Preserve the shared input directory used by all
  227. tests in this class.
  228. preserve_outdir: Preserve the output directories used by tests. Each
  229. test has its own, so this is normally only useful when running a
  230. single test.
  231. toolpath: ist of paths to use for tools
  232. """
  233. cls.preserve_indir = preserve_indir
  234. cls.preserve_outdirs = preserve_outdirs
  235. cls.toolpath = toolpath
  236. cls.verbosity = verbosity
  237. def _CheckBintool(self, bintool):
  238. if not bintool.is_present():
  239. self.skipTest('%s not available' % bintool.name)
  240. def _CheckLz4(self):
  241. bintool = self.comp_bintools['lz4']
  242. self._CheckBintool(bintool)
  243. def _CleanupOutputDir(self):
  244. """Remove the temporary output directory"""
  245. if self.preserve_outdirs:
  246. print('Preserving output dir: %s' % tools.outdir)
  247. else:
  248. tools._finalise_for_test()
  249. def setUp(self):
  250. # Enable this to turn on debugging output
  251. # tout.init(tout.DEBUG)
  252. command.test_result = None
  253. def tearDown(self):
  254. """Remove the temporary output directory"""
  255. self._CleanupOutputDir()
  256. def _SetupImageInTmpdir(self):
  257. """Set up the output image in a new temporary directory
  258. This is used when an image has been generated in the output directory,
  259. but we want to run binman again. This will create a new output
  260. directory and fail to delete the original one.
  261. This creates a new temporary directory, copies the image to it (with a
  262. new name) and removes the old output directory.
  263. Returns:
  264. Tuple:
  265. Temporary directory to use
  266. New image filename
  267. """
  268. image_fname = tools.get_output_filename('image.bin')
  269. tmpdir = tempfile.mkdtemp(prefix='binman.')
  270. updated_fname = os.path.join(tmpdir, 'image-updated.bin')
  271. tools.write_file(updated_fname, tools.read_file(image_fname))
  272. self._CleanupOutputDir()
  273. return tmpdir, updated_fname
  274. @classmethod
  275. def _ResetDtbs(cls):
  276. TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
  277. TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
  278. TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
  279. TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
  280. def _RunBinman(self, *args, **kwargs):
  281. """Run binman using the command line
  282. Args:
  283. Arguments to pass, as a list of strings
  284. kwargs: Arguments to pass to Command.RunPipe()
  285. """
  286. result = command.run_pipe([[self._binman_pathname] + list(args)],
  287. capture=True, capture_stderr=True, raise_on_error=False)
  288. if result.return_code and kwargs.get('raise_on_error', True):
  289. raise Exception("Error running '%s': %s" % (' '.join(args),
  290. result.stdout + result.stderr))
  291. return result
  292. def _DoBinman(self, *argv):
  293. """Run binman using directly (in the same process)
  294. Args:
  295. Arguments to pass, as a list of strings
  296. Returns:
  297. Return value (0 for success)
  298. """
  299. argv = list(argv)
  300. args = cmdline.ParseArgs(argv)
  301. args.pager = 'binman-invalid-pager'
  302. args.build_dir = self._indir
  303. # For testing, you can force an increase in verbosity here
  304. # args.verbosity = tout.DEBUG
  305. return control.Binman(args)
  306. def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
  307. entry_args=None, images=None, use_real_dtb=False,
  308. use_expanded=False, verbosity=None, allow_missing=False,
  309. allow_fake_blobs=False, extra_indirs=None, threads=None,
  310. test_section_timeout=False, update_fdt_in_elf=None,
  311. force_missing_bintools='', ignore_missing=False, output_dir=None):
  312. """Run binman with a given test file
  313. Args:
  314. fname: Device-tree source filename to use (e.g. 005_simple.dts)
  315. debug: True to enable debugging output
  316. map: True to output map files for the images
  317. update_dtb: Update the offset and size of each entry in the device
  318. tree before packing it into the image
  319. entry_args: Dict of entry args to supply to binman
  320. key: arg name
  321. value: value of that arg
  322. images: List of image names to build
  323. use_real_dtb: True to use the test file as the contents of
  324. the u-boot-dtb entry. Normally this is not needed and the
  325. test contents (the U_BOOT_DTB_DATA string) can be used.
  326. But in some test we need the real contents.
  327. use_expanded: True to use expanded entries where available, e.g.
  328. 'u-boot-expanded' instead of 'u-boot'
  329. verbosity: Verbosity level to use (0-3, None=don't set it)
  330. allow_missing: Set the '--allow-missing' flag so that missing
  331. external binaries just produce a warning instead of an error
  332. allow_fake_blobs: Set the '--fake-ext-blobs' flag
  333. extra_indirs: Extra input directories to add using -I
  334. threads: Number of threads to use (None for default, 0 for
  335. single-threaded)
  336. test_section_timeout: True to force the first time to timeout, as
  337. used in testThreadTimeout()
  338. update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
  339. force_missing_tools (str): comma-separated list of bintools to
  340. regard as missing
  341. output_dir: Specific output directory to use for image using -O
  342. Returns:
  343. int return code, 0 on success
  344. """
  345. args = []
  346. if debug:
  347. args.append('-D')
  348. if verbosity is not None:
  349. args.append('-v%d' % verbosity)
  350. elif self.verbosity:
  351. args.append('-v%d' % self.verbosity)
  352. if self.toolpath:
  353. for path in self.toolpath:
  354. args += ['--toolpath', path]
  355. if threads is not None:
  356. args.append('-T%d' % threads)
  357. if test_section_timeout:
  358. args.append('--test-section-timeout')
  359. args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
  360. if map:
  361. args.append('-m')
  362. if update_dtb:
  363. args.append('-u')
  364. if not use_real_dtb:
  365. args.append('--fake-dtb')
  366. if not use_expanded:
  367. args.append('--no-expanded')
  368. if entry_args:
  369. for arg, value in entry_args.items():
  370. args.append('-a%s=%s' % (arg, value))
  371. if allow_missing:
  372. args.append('-M')
  373. if ignore_missing:
  374. args.append('-W')
  375. if allow_fake_blobs:
  376. args.append('--fake-ext-blobs')
  377. if force_missing_bintools:
  378. args += ['--force-missing-bintools', force_missing_bintools]
  379. if update_fdt_in_elf:
  380. args += ['--update-fdt-in-elf', update_fdt_in_elf]
  381. if images:
  382. for image in images:
  383. args += ['-i', image]
  384. if extra_indirs:
  385. for indir in extra_indirs:
  386. args += ['-I', indir]
  387. if output_dir:
  388. args += ['-O', output_dir]
  389. return self._DoBinman(*args)
  390. def _SetupDtb(self, fname, outfile='u-boot.dtb'):
  391. """Set up a new test device-tree file
  392. The given file is compiled and set up as the device tree to be used
  393. for ths test.
  394. Args:
  395. fname: Filename of .dts file to read
  396. outfile: Output filename for compiled device-tree binary
  397. Returns:
  398. Contents of device-tree binary
  399. """
  400. tmpdir = tempfile.mkdtemp(prefix='binmant.')
  401. dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
  402. with open(dtb, 'rb') as fd:
  403. data = fd.read()
  404. TestFunctional._MakeInputFile(outfile, data)
  405. shutil.rmtree(tmpdir)
  406. return data
  407. def _GetDtbContentsForSpls(self, dtb_data, name):
  408. """Create a version of the main DTB for SPL / TPL / VPL
  409. For testing we don't actually have different versions of the DTB. With
  410. U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
  411. we don't normally have any unwanted nodes.
  412. We still want the DTBs for SPL and TPL to be different though, since
  413. otherwise it is confusing to know which one we are looking at. So add
  414. an 'spl' or 'tpl' property to the top-level node.
  415. Args:
  416. dtb_data: dtb data to modify (this should be a value devicetree)
  417. name: Name of a new property to add
  418. Returns:
  419. New dtb data with the property added
  420. """
  421. dtb = fdt.Fdt.FromData(dtb_data)
  422. dtb.Scan()
  423. dtb.GetNode('/binman').AddZeroProp(name)
  424. dtb.Sync(auto_resize=True)
  425. dtb.Pack()
  426. return dtb.GetContents()
  427. def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
  428. map=False, update_dtb=False, entry_args=None,
  429. reset_dtbs=True, extra_indirs=None, threads=None):
  430. """Run binman and return the resulting image
  431. This runs binman with a given test file and then reads the resulting
  432. output file. It is a shortcut function since most tests need to do
  433. these steps.
  434. Raises an assertion failure if binman returns a non-zero exit code.
  435. Args:
  436. fname: Device-tree source filename to use (e.g. 005_simple.dts)
  437. use_real_dtb: True to use the test file as the contents of
  438. the u-boot-dtb entry. Normally this is not needed and the
  439. test contents (the U_BOOT_DTB_DATA string) can be used.
  440. But in some test we need the real contents.
  441. use_expanded: True to use expanded entries where available, e.g.
  442. 'u-boot-expanded' instead of 'u-boot'
  443. map: True to output map files for the images
  444. update_dtb: Update the offset and size of each entry in the device
  445. tree before packing it into the image
  446. entry_args: Dict of entry args to supply to binman
  447. key: arg name
  448. value: value of that arg
  449. reset_dtbs: With use_real_dtb the test dtb is overwritten by this
  450. function. If reset_dtbs is True, then the original test dtb
  451. is written back before this function finishes
  452. extra_indirs: Extra input directories to add using -I
  453. threads: Number of threads to use (None for default, 0 for
  454. single-threaded)
  455. Returns:
  456. Tuple:
  457. Resulting image contents
  458. Device tree contents
  459. Map data showing contents of image (or None if none)
  460. Output device tree binary filename ('u-boot.dtb' path)
  461. """
  462. dtb_data = None
  463. # Use the compiled test file as the u-boot-dtb input
  464. if use_real_dtb:
  465. dtb_data = self._SetupDtb(fname)
  466. # For testing purposes, make a copy of the DT for SPL and TPL. Add
  467. # a node indicating which it is, so aid verification.
  468. for name in ['spl', 'tpl', 'vpl']:
  469. dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
  470. outfile = os.path.join(self._indir, dtb_fname)
  471. TestFunctional._MakeInputFile(dtb_fname,
  472. self._GetDtbContentsForSpls(dtb_data, name))
  473. try:
  474. retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
  475. entry_args=entry_args, use_real_dtb=use_real_dtb,
  476. use_expanded=use_expanded, extra_indirs=extra_indirs,
  477. threads=threads)
  478. self.assertEqual(0, retcode)
  479. out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
  480. # Find the (only) image, read it and return its contents
  481. image = control.images['image']
  482. image_fname = tools.get_output_filename('image.bin')
  483. self.assertTrue(os.path.exists(image_fname))
  484. if map:
  485. map_fname = tools.get_output_filename('image.map')
  486. with open(map_fname) as fd:
  487. map_data = fd.read()
  488. else:
  489. map_data = None
  490. with open(image_fname, 'rb') as fd:
  491. return fd.read(), dtb_data, map_data, out_dtb_fname
  492. finally:
  493. # Put the test file back
  494. if reset_dtbs and use_real_dtb:
  495. self._ResetDtbs()
  496. def _DoReadFileRealDtb(self, fname):
  497. """Run binman with a real .dtb file and return the resulting data
  498. Args:
  499. fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
  500. Returns:
  501. Resulting image contents
  502. """
  503. return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
  504. def _DoReadFile(self, fname, use_real_dtb=False):
  505. """Helper function which discards the device-tree binary
  506. Args:
  507. fname: Device-tree source filename to use (e.g. 005_simple.dts)
  508. use_real_dtb: True to use the test file as the contents of
  509. the u-boot-dtb entry. Normally this is not needed and the
  510. test contents (the U_BOOT_DTB_DATA string) can be used.
  511. But in some test we need the real contents.
  512. Returns:
  513. Resulting image contents
  514. """
  515. return self._DoReadFileDtb(fname, use_real_dtb)[0]
  516. @classmethod
  517. def _MakeInputFile(cls, fname, contents):
  518. """Create a new test input file, creating directories as needed
  519. Args:
  520. fname: Filename to create
  521. contents: File contents to write in to the file
  522. Returns:
  523. Full pathname of file created
  524. """
  525. pathname = os.path.join(cls._indir, fname)
  526. dirname = os.path.dirname(pathname)
  527. if dirname and not os.path.exists(dirname):
  528. os.makedirs(dirname)
  529. with open(pathname, 'wb') as fd:
  530. fd.write(contents)
  531. return pathname
  532. @classmethod
  533. def _MakeInputDir(cls, dirname):
  534. """Create a new test input directory, creating directories as needed
  535. Args:
  536. dirname: Directory name to create
  537. Returns:
  538. Full pathname of directory created
  539. """
  540. pathname = os.path.join(cls._indir, dirname)
  541. if not os.path.exists(pathname):
  542. os.makedirs(pathname)
  543. return pathname
  544. @classmethod
  545. def _SetupSplElf(cls, src_fname='bss_data'):
  546. """Set up an ELF file with a '_dt_ucode_base_size' symbol
  547. Args:
  548. Filename of ELF file to use as SPL
  549. """
  550. TestFunctional._MakeInputFile('spl/u-boot-spl',
  551. tools.read_file(cls.ElfTestFile(src_fname)))
  552. @classmethod
  553. def _SetupTplElf(cls, src_fname='bss_data'):
  554. """Set up an ELF file with a '_dt_ucode_base_size' symbol
  555. Args:
  556. Filename of ELF file to use as TPL
  557. """
  558. TestFunctional._MakeInputFile('tpl/u-boot-tpl',
  559. tools.read_file(cls.ElfTestFile(src_fname)))
  560. @classmethod
  561. def _SetupVplElf(cls, src_fname='bss_data'):
  562. """Set up an ELF file with a '_dt_ucode_base_size' symbol
  563. Args:
  564. Filename of ELF file to use as VPL
  565. """
  566. TestFunctional._MakeInputFile('vpl/u-boot-vpl',
  567. tools.read_file(cls.ElfTestFile(src_fname)))
  568. @classmethod
  569. def _SetupPmuFwlElf(cls, src_fname='bss_data'):
  570. """Set up an ELF file with a '_dt_ucode_base_size' symbol
  571. Args:
  572. Filename of ELF file to use as VPL
  573. """
  574. TestFunctional._MakeInputFile('pmu-firmware.elf',
  575. tools.read_file(cls.ElfTestFile(src_fname)))
  576. @classmethod
  577. def _SetupDescriptor(cls):
  578. with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
  579. TestFunctional._MakeInputFile('descriptor.bin', fd.read())
  580. @classmethod
  581. def TestFile(cls, fname):
  582. return os.path.join(cls._binman_dir, 'test', fname)
  583. @classmethod
  584. def ElfTestFile(cls, fname):
  585. return os.path.join(cls._elf_testdir, fname)
  586. @classmethod
  587. def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
  588. init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
  589. data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
  590. dummy, paged_sz) + U_BOOT_DATA
  591. data += extra_data
  592. TestFunctional._MakeInputFile(fname, data)
  593. def AssertInList(self, grep_list, target):
  594. """Assert that at least one of a list of things is in a target
  595. Args:
  596. grep_list: List of strings to check
  597. target: Target string
  598. """
  599. for grep in grep_list:
  600. if grep in target:
  601. return
  602. self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
  603. def CheckNoGaps(self, entries):
  604. """Check that all entries fit together without gaps
  605. Args:
  606. entries: List of entries to check
  607. """
  608. offset = 0
  609. for entry in entries.values():
  610. self.assertEqual(offset, entry.offset)
  611. offset += entry.size
  612. def GetFdtLen(self, dtb):
  613. """Get the totalsize field from a device-tree binary
  614. Args:
  615. dtb: Device-tree binary contents
  616. Returns:
  617. Total size of device-tree binary, from the header
  618. """
  619. return struct.unpack('>L', dtb[4:8])[0]
  620. def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
  621. def AddNode(node, path):
  622. if node.name != '/':
  623. path += '/' + node.name
  624. for prop in node.props.values():
  625. if prop.name in prop_names:
  626. prop_path = path + ':' + prop.name
  627. tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
  628. prop.value)
  629. for subnode in node.subnodes:
  630. AddNode(subnode, path)
  631. tree = {}
  632. AddNode(dtb.GetRoot(), '')
  633. return tree
  634. def _CheckSign(self, fit, key):
  635. try:
  636. tools.run('fit_check_sign', '-k', key, '-f', fit)
  637. except:
  638. self.fail('Expected signed FIT container')
  639. return False
  640. return True
  641. def testRun(self):
  642. """Test a basic run with valid args"""
  643. result = self._RunBinman('-h')
  644. def testFullHelp(self):
  645. """Test that the full help is displayed with -H"""
  646. result = self._RunBinman('-H')
  647. help_file = os.path.join(self._binman_dir, 'README.rst')
  648. # Remove possible extraneous strings
  649. extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
  650. gothelp = result.stdout.replace(extra, '')
  651. self.assertEqual(len(gothelp), os.path.getsize(help_file))
  652. self.assertEqual(0, len(result.stderr))
  653. self.assertEqual(0, result.return_code)
  654. def testFullHelpInternal(self):
  655. """Test that the full help is displayed with -H"""
  656. try:
  657. command.test_result = command.CommandResult()
  658. result = self._DoBinman('-H')
  659. help_file = os.path.join(self._binman_dir, 'README.rst')
  660. finally:
  661. command.test_result = None
  662. def testHelp(self):
  663. """Test that the basic help is displayed with -h"""
  664. result = self._RunBinman('-h')
  665. self.assertTrue(len(result.stdout) > 200)
  666. self.assertEqual(0, len(result.stderr))
  667. self.assertEqual(0, result.return_code)
  668. def testBoard(self):
  669. """Test that we can run it with a specific board"""
  670. self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
  671. TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
  672. result = self._DoBinman('build', '-n', '-b', 'sandbox')
  673. self.assertEqual(0, result)
  674. def testNeedBoard(self):
  675. """Test that we get an error when no board ius supplied"""
  676. with self.assertRaises(ValueError) as e:
  677. result = self._DoBinman('build')
  678. self.assertIn("Must provide a board to process (use -b <board>)",
  679. str(e.exception))
  680. def testMissingDt(self):
  681. """Test that an invalid device-tree file generates an error"""
  682. with self.assertRaises(Exception) as e:
  683. self._RunBinman('build', '-d', 'missing_file')
  684. # We get one error from libfdt, and a different one from fdtget.
  685. self.AssertInList(["Couldn't open blob from 'missing_file'",
  686. 'No such file or directory'], str(e.exception))
  687. def testBrokenDt(self):
  688. """Test that an invalid device-tree source file generates an error
  689. Since this is a source file it should be compiled and the error
  690. will come from the device-tree compiler (dtc).
  691. """
  692. with self.assertRaises(Exception) as e:
  693. self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
  694. self.assertIn("FATAL ERROR: Unable to parse input tree",
  695. str(e.exception))
  696. def testMissingNode(self):
  697. """Test that a device tree without a 'binman' node generates an error"""
  698. with self.assertRaises(Exception) as e:
  699. self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
  700. self.assertIn("does not have a 'binman' node", str(e.exception))
  701. def testEmpty(self):
  702. """Test that an empty binman node works OK (i.e. does nothing)"""
  703. result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
  704. self.assertEqual(0, len(result.stderr))
  705. self.assertEqual(0, result.return_code)
  706. def testInvalidEntry(self):
  707. """Test that an invalid entry is flagged"""
  708. with self.assertRaises(Exception) as e:
  709. result = self._RunBinman('build', '-d',
  710. self.TestFile('004_invalid_entry.dts'))
  711. self.assertIn("Unknown entry type 'not-a-valid-type' in node "
  712. "'/binman/not-a-valid-type'", str(e.exception))
  713. def testSimple(self):
  714. """Test a simple binman with a single file"""
  715. data = self._DoReadFile('005_simple.dts')
  716. self.assertEqual(U_BOOT_DATA, data)
  717. def testSimpleDebug(self):
  718. """Test a simple binman run with debugging enabled"""
  719. self._DoTestFile('005_simple.dts', debug=True)
  720. def testDual(self):
  721. """Test that we can handle creating two images
  722. This also tests image padding.
  723. """
  724. retcode = self._DoTestFile('006_dual_image.dts')
  725. self.assertEqual(0, retcode)
  726. image = control.images['image1']
  727. self.assertEqual(len(U_BOOT_DATA), image.size)
  728. fname = tools.get_output_filename('image1.bin')
  729. self.assertTrue(os.path.exists(fname))
  730. with open(fname, 'rb') as fd:
  731. data = fd.read()
  732. self.assertEqual(U_BOOT_DATA, data)
  733. image = control.images['image2']
  734. self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
  735. fname = tools.get_output_filename('image2.bin')
  736. self.assertTrue(os.path.exists(fname))
  737. with open(fname, 'rb') as fd:
  738. data = fd.read()
  739. self.assertEqual(U_BOOT_DATA, data[3:7])
  740. self.assertEqual(tools.get_bytes(0, 3), data[:3])
  741. self.assertEqual(tools.get_bytes(0, 5), data[7:])
  742. def testBadAlign(self):
  743. """Test that an invalid alignment value is detected"""
  744. with self.assertRaises(ValueError) as e:
  745. self._DoTestFile('007_bad_align.dts')
  746. self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
  747. "of two", str(e.exception))
  748. def testPackSimple(self):
  749. """Test that packing works as expected"""
  750. retcode = self._DoTestFile('008_pack.dts')
  751. self.assertEqual(0, retcode)
  752. self.assertIn('image', control.images)
  753. image = control.images['image']
  754. entries = image.GetEntries()
  755. self.assertEqual(5, len(entries))
  756. # First u-boot
  757. self.assertIn('u-boot', entries)
  758. entry = entries['u-boot']
  759. self.assertEqual(0, entry.offset)
  760. self.assertEqual(len(U_BOOT_DATA), entry.size)
  761. # Second u-boot, aligned to 16-byte boundary
  762. self.assertIn('u-boot-align', entries)
  763. entry = entries['u-boot-align']
  764. self.assertEqual(16, entry.offset)
  765. self.assertEqual(len(U_BOOT_DATA), entry.size)
  766. # Third u-boot, size 23 bytes
  767. self.assertIn('u-boot-size', entries)
  768. entry = entries['u-boot-size']
  769. self.assertEqual(20, entry.offset)
  770. self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
  771. self.assertEqual(23, entry.size)
  772. # Fourth u-boot, placed immediate after the above
  773. self.assertIn('u-boot-next', entries)
  774. entry = entries['u-boot-next']
  775. self.assertEqual(43, entry.offset)
  776. self.assertEqual(len(U_BOOT_DATA), entry.size)
  777. # Fifth u-boot, placed at a fixed offset
  778. self.assertIn('u-boot-fixed', entries)
  779. entry = entries['u-boot-fixed']
  780. self.assertEqual(61, entry.offset)
  781. self.assertEqual(len(U_BOOT_DATA), entry.size)
  782. self.assertEqual(65, image.size)
  783. def testPackExtra(self):
  784. """Test that extra packing feature works as expected"""
  785. data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
  786. update_dtb=True)
  787. self.assertIn('image', control.images)
  788. image = control.images['image']
  789. entries = image.GetEntries()
  790. self.assertEqual(6, len(entries))
  791. # First u-boot with padding before and after (included in minimum size)
  792. self.assertIn('u-boot', entries)
  793. entry = entries['u-boot']
  794. self.assertEqual(0, entry.offset)
  795. self.assertEqual(3, entry.pad_before)
  796. self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
  797. self.assertEqual(U_BOOT_DATA, entry.data)
  798. self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
  799. tools.get_bytes(0, 5), data[:entry.size])
  800. pos = entry.size
  801. # Second u-boot has an aligned size, but it has no effect
  802. self.assertIn('u-boot-align-size-nop', entries)
  803. entry = entries['u-boot-align-size-nop']
  804. self.assertEqual(pos, entry.offset)
  805. self.assertEqual(len(U_BOOT_DATA), entry.size)
  806. self.assertEqual(U_BOOT_DATA, entry.data)
  807. self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
  808. pos += entry.size
  809. # Third u-boot has an aligned size too
  810. self.assertIn('u-boot-align-size', entries)
  811. entry = entries['u-boot-align-size']
  812. self.assertEqual(pos, entry.offset)
  813. self.assertEqual(32, entry.size)
  814. self.assertEqual(U_BOOT_DATA, entry.data)
  815. self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
  816. data[pos:pos + entry.size])
  817. pos += entry.size
  818. # Fourth u-boot has an aligned end
  819. self.assertIn('u-boot-align-end', entries)
  820. entry = entries['u-boot-align-end']
  821. self.assertEqual(48, entry.offset)
  822. self.assertEqual(16, entry.size)
  823. self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
  824. self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
  825. data[pos:pos + entry.size])
  826. pos += entry.size
  827. # Fifth u-boot immediately afterwards
  828. self.assertIn('u-boot-align-both', entries)
  829. entry = entries['u-boot-align-both']
  830. self.assertEqual(64, entry.offset)
  831. self.assertEqual(64, entry.size)
  832. self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
  833. self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
  834. data[pos:pos + entry.size])
  835. # Sixth u-boot with both minimum size and aligned size
  836. self.assertIn('u-boot-min-size', entries)
  837. entry = entries['u-boot-min-size']
  838. self.assertEqual(128, entry.offset)
  839. self.assertEqual(32, entry.size)
  840. self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
  841. self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
  842. data[pos:pos + entry.size])
  843. self.CheckNoGaps(entries)
  844. self.assertEqual(160, image.size)
  845. dtb = fdt.Fdt(out_dtb_fname)
  846. dtb.Scan()
  847. props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
  848. expected = {
  849. 'image-pos': 0,
  850. 'offset': 0,
  851. 'size': 160,
  852. 'u-boot:image-pos': 0,
  853. 'u-boot:offset': 0,
  854. 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
  855. 'u-boot-align-size-nop:image-pos': 12,
  856. 'u-boot-align-size-nop:offset': 12,
  857. 'u-boot-align-size-nop:size': 4,
  858. 'u-boot-align-size:image-pos': 16,
  859. 'u-boot-align-size:offset': 16,
  860. 'u-boot-align-size:size': 32,
  861. 'u-boot-align-end:image-pos': 48,
  862. 'u-boot-align-end:offset': 48,
  863. 'u-boot-align-end:size': 16,
  864. 'u-boot-align-both:image-pos': 64,
  865. 'u-boot-align-both:offset': 64,
  866. 'u-boot-align-both:size': 64,
  867. 'u-boot-min-size:image-pos': 128,
  868. 'u-boot-min-size:offset': 128,
  869. 'u-boot-min-size:size': 32,
  870. }
  871. self.assertEqual(expected, props)
  872. def testPackAlignPowerOf2(self):
  873. """Test that invalid entry alignment is detected"""
  874. with self.assertRaises(ValueError) as e:
  875. self._DoTestFile('010_pack_align_power2.dts')
  876. self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
  877. "of two", str(e.exception))
  878. def testPackAlignSizePowerOf2(self):
  879. """Test that invalid entry size alignment is detected"""
  880. with self.assertRaises(ValueError) as e:
  881. self._DoTestFile('011_pack_align_size_power2.dts')
  882. self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
  883. "power of two", str(e.exception))
  884. def testPackInvalidAlign(self):
  885. """Test detection of an offset that does not match its alignment"""
  886. with self.assertRaises(ValueError) as e:
  887. self._DoTestFile('012_pack_inv_align.dts')
  888. self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
  889. "align 0x4 (4)", str(e.exception))
  890. def testPackInvalidSizeAlign(self):
  891. """Test that invalid entry size alignment is detected"""
  892. with self.assertRaises(ValueError) as e:
  893. self._DoTestFile('013_pack_inv_size_align.dts')
  894. self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
  895. "align-size 0x4 (4)", str(e.exception))
  896. def testPackOverlap(self):
  897. """Test that overlapping regions are detected"""
  898. with self.assertRaises(ValueError) as e:
  899. self._DoTestFile('014_pack_overlap.dts')
  900. self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
  901. "with previous entry '/binman/u-boot' ending at 0x4 (4)",
  902. str(e.exception))
  903. def testPackEntryOverflow(self):
  904. """Test that entries that overflow their size are detected"""
  905. with self.assertRaises(ValueError) as e:
  906. self._DoTestFile('015_pack_overflow.dts')
  907. self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
  908. "but entry size is 0x3 (3)", str(e.exception))
  909. def testPackImageOverflow(self):
  910. """Test that entries which overflow the image size are detected"""
  911. with self.assertRaises(ValueError) as e:
  912. self._DoTestFile('016_pack_image_overflow.dts')
  913. self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
  914. "size 0x3 (3)", str(e.exception))
  915. def testPackImageSize(self):
  916. """Test that the image size can be set"""
  917. retcode = self._DoTestFile('017_pack_image_size.dts')
  918. self.assertEqual(0, retcode)
  919. self.assertIn('image', control.images)
  920. image = control.images['image']
  921. self.assertEqual(7, image.size)
  922. def testPackImageSizeAlign(self):
  923. """Test that image size alignemnt works as expected"""
  924. retcode = self._DoTestFile('018_pack_image_align.dts')
  925. self.assertEqual(0, retcode)
  926. self.assertIn('image', control.images)
  927. image = control.images['image']
  928. self.assertEqual(16, image.size)
  929. def testPackInvalidImageAlign(self):
  930. """Test that invalid image alignment is detected"""
  931. with self.assertRaises(ValueError) as e:
  932. self._DoTestFile('019_pack_inv_image_align.dts')
  933. self.assertIn("Section '/binman': Size 0x7 (7) does not match "
  934. "align-size 0x8 (8)", str(e.exception))
  935. def testPackAlignPowerOf2Inv(self):
  936. """Test that invalid image alignment is detected"""
  937. with self.assertRaises(ValueError) as e:
  938. self._DoTestFile('020_pack_inv_image_align_power2.dts')
  939. self.assertIn("Image '/binman': Alignment size 131 must be a power of "
  940. "two", str(e.exception))
  941. def testImagePadByte(self):
  942. """Test that the image pad byte can be specified"""
  943. self._SetupSplElf()
  944. data = self._DoReadFile('021_image_pad.dts')
  945. self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
  946. U_BOOT_DATA, data)
  947. def testImageName(self):
  948. """Test that image files can be named"""
  949. retcode = self._DoTestFile('022_image_name.dts')
  950. self.assertEqual(0, retcode)
  951. image = control.images['image1']
  952. fname = tools.get_output_filename('test-name')
  953. self.assertTrue(os.path.exists(fname))
  954. image = control.images['image2']
  955. fname = tools.get_output_filename('test-name.xx')
  956. self.assertTrue(os.path.exists(fname))
  957. def testBlobFilename(self):
  958. """Test that generic blobs can be provided by filename"""
  959. data = self._DoReadFile('023_blob.dts')
  960. self.assertEqual(BLOB_DATA, data)
  961. def testPackSorted(self):
  962. """Test that entries can be sorted"""
  963. self._SetupSplElf()
  964. data = self._DoReadFile('024_sorted.dts')
  965. self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
  966. tools.get_bytes(0, 2) + U_BOOT_DATA, data)
  967. def testPackZeroOffset(self):
  968. """Test that an entry at offset 0 is not given a new offset"""
  969. self._SetupSplElf()
  970. with self.assertRaises(ValueError) as e:
  971. self._DoTestFile('025_pack_zero_size.dts')
  972. self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
  973. "with previous entry '/binman/u-boot' ending at 0x4 (4)",
  974. str(e.exception))
  975. def testPackUbootDtb(self):
  976. """Test that a device tree can be added to U-Boot"""
  977. data = self._DoReadFile('026_pack_u_boot_dtb.dts')
  978. self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
  979. def testPackX86RomNoSize(self):
  980. """Test that the end-at-4gb property requires a size property"""
  981. self._SetupSplElf()
  982. with self.assertRaises(ValueError) as e:
  983. self._DoTestFile('027_pack_4gb_no_size.dts')
  984. self.assertIn("Image '/binman': Section size must be provided when "
  985. "using end-at-4gb", str(e.exception))
  986. def test4gbAndSkipAtStartTogether(self):
  987. """Test that the end-at-4gb and skip-at-size property can't be used
  988. together"""
  989. self._SetupSplElf()
  990. with self.assertRaises(ValueError) as e:
  991. self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
  992. self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
  993. "'skip-at-start'", str(e.exception))
  994. def testPackX86RomOutside(self):
  995. """Test that the end-at-4gb property checks for offset boundaries"""
  996. self._SetupSplElf()
  997. with self.assertRaises(ValueError) as e:
  998. self._DoTestFile('028_pack_4gb_outside.dts')
  999. self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
  1000. "is outside the section '/binman' starting at "
  1001. '0xffffffe0 (4294967264) of size 0x20 (32)',
  1002. str(e.exception))
  1003. def testPackX86Rom(self):
  1004. """Test that a basic x86 ROM can be created"""
  1005. self._SetupSplElf()
  1006. data = self._DoReadFile('029_x86_rom.dts')
  1007. self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
  1008. tools.get_bytes(0, 2), data)
  1009. def testPackX86RomMeNoDesc(self):
  1010. """Test that an invalid Intel descriptor entry is detected"""
  1011. try:
  1012. TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
  1013. with self.assertRaises(ValueError) as e:
  1014. self._DoTestFile('163_x86_rom_me_empty.dts')
  1015. self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
  1016. str(e.exception))
  1017. finally:
  1018. self._SetupDescriptor()
  1019. def testPackX86RomBadDesc(self):
  1020. """Test that the Intel requires a descriptor entry"""
  1021. with self.assertRaises(ValueError) as e:
  1022. self._DoTestFile('030_x86_rom_me_no_desc.dts')
  1023. self.assertIn("Node '/binman/intel-me': No offset set with "
  1024. "offset-unset: should another entry provide this correct "
  1025. "offset?", str(e.exception))
  1026. def testPackX86RomMe(self):
  1027. """Test that an x86 ROM with an ME region can be created"""
  1028. data = self._DoReadFile('031_x86_rom_me.dts')
  1029. expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
  1030. if data[:0x1000] != expected_desc:
  1031. self.fail('Expected descriptor binary at start of image')
  1032. self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
  1033. def testPackVga(self):
  1034. """Test that an image with a VGA binary can be created"""
  1035. data = self._DoReadFile('032_intel_vga.dts')
  1036. self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
  1037. def testPackStart16(self):
  1038. """Test that an image with an x86 start16 region can be created"""
  1039. data = self._DoReadFile('033_x86_start16.dts')
  1040. self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
  1041. def testPackPowerpcMpc85xxBootpgResetvec(self):
  1042. """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
  1043. created"""
  1044. data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
  1045. self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
  1046. def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
  1047. """Handle running a test for insertion of microcode
  1048. Args:
  1049. dts_fname: Name of test .dts file
  1050. nodtb_data: Data that we expect in the first section
  1051. ucode_second: True if the microsecond entry is second instead of
  1052. third
  1053. Returns:
  1054. Tuple:
  1055. Contents of first region (U-Boot or SPL)
  1056. Offset and size components of microcode pointer, as inserted
  1057. in the above (two 4-byte words)
  1058. """
  1059. data = self._DoReadFile(dts_fname, True)
  1060. # Now check the device tree has no microcode
  1061. if ucode_second:
  1062. ucode_content = data[len(nodtb_data):]
  1063. ucode_pos = len(nodtb_data)
  1064. dtb_with_ucode = ucode_content[16:]
  1065. fdt_len = self.GetFdtLen(dtb_with_ucode)
  1066. else:
  1067. dtb_with_ucode = data[len(nodtb_data):]
  1068. fdt_len = self.GetFdtLen(dtb_with_ucode)
  1069. ucode_content = dtb_with_ucode[fdt_len:]
  1070. ucode_pos = len(nodtb_data) + fdt_len
  1071. fname = tools.get_output_filename('test.dtb')
  1072. with open(fname, 'wb') as fd:
  1073. fd.write(dtb_with_ucode)
  1074. dtb = fdt.FdtScan(fname)
  1075. ucode = dtb.GetNode('/microcode')
  1076. self.assertTrue(ucode)
  1077. for node in ucode.subnodes:
  1078. self.assertFalse(node.props.get('data'))
  1079. # Check that the microcode appears immediately after the Fdt
  1080. # This matches the concatenation of the data properties in
  1081. # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
  1082. ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
  1083. 0x78235609)
  1084. self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
  1085. # Check that the microcode pointer was inserted. It should match the
  1086. # expected offset and size
  1087. pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
  1088. len(ucode_data))
  1089. u_boot = data[:len(nodtb_data)]
  1090. return u_boot, pos_and_size
  1091. def testPackUbootMicrocode(self):
  1092. """Test that x86 microcode can be handled correctly
  1093. We expect to see the following in the image, in order:
  1094. u-boot-nodtb.bin with a microcode pointer inserted at the correct
  1095. place
  1096. u-boot.dtb with the microcode removed
  1097. the microcode
  1098. """
  1099. first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
  1100. U_BOOT_NODTB_DATA)
  1101. self.assertEqual(b'nodtb with microcode' + pos_and_size +
  1102. b' somewhere in here', first)
  1103. def _RunPackUbootSingleMicrocode(self):
  1104. """Test that x86 microcode can be handled correctly
  1105. We expect to see the following in the image, in order:
  1106. u-boot-nodtb.bin with a microcode pointer inserted at the correct
  1107. place
  1108. u-boot.dtb with the microcode
  1109. an empty microcode region
  1110. """
  1111. # We need the libfdt library to run this test since only that allows
  1112. # finding the offset of a property. This is required by
  1113. # Entry_u_boot_dtb_with_ucode.ObtainContents().
  1114. data = self._DoReadFile('035_x86_single_ucode.dts', True)
  1115. second = data[len(U_BOOT_NODTB_DATA):]
  1116. fdt_len = self.GetFdtLen(second)
  1117. third = second[fdt_len:]
  1118. second = second[:fdt_len]
  1119. ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
  1120. self.assertIn(ucode_data, second)
  1121. ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
  1122. # Check that the microcode pointer was inserted. It should match the
  1123. # expected offset and size
  1124. pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
  1125. len(ucode_data))
  1126. first = data[:len(U_BOOT_NODTB_DATA)]
  1127. self.assertEqual(b'nodtb with microcode' + pos_and_size +
  1128. b' somewhere in here', first)
  1129. def testPackUbootSingleMicrocode(self):
  1130. """Test that x86 microcode can be handled correctly with fdt_normal.
  1131. """
  1132. self._RunPackUbootSingleMicrocode()
  1133. def testUBootImg(self):
  1134. """Test that u-boot.img can be put in a file"""
  1135. data = self._DoReadFile('036_u_boot_img.dts')
  1136. self.assertEqual(U_BOOT_IMG_DATA, data)
  1137. def testNoMicrocode(self):
  1138. """Test that a missing microcode region is detected"""
  1139. with self.assertRaises(ValueError) as e:
  1140. self._DoReadFile('037_x86_no_ucode.dts', True)
  1141. self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
  1142. "node found in ", str(e.exception))
  1143. def testMicrocodeWithoutNode(self):
  1144. """Test that a missing u-boot-dtb-with-ucode node is detected"""
  1145. with self.assertRaises(ValueError) as e:
  1146. self._DoReadFile('038_x86_ucode_missing_node.dts', True)
  1147. self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
  1148. "microcode region u-boot-dtb-with-ucode", str(e.exception))
  1149. def testMicrocodeWithoutNode2(self):
  1150. """Test that a missing u-boot-ucode node is detected"""
  1151. with self.assertRaises(ValueError) as e:
  1152. self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
  1153. self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
  1154. "microcode region u-boot-ucode", str(e.exception))
  1155. def testMicrocodeWithoutPtrInElf(self):
  1156. """Test that a U-Boot binary without the microcode symbol is detected"""
  1157. # ELF file without a '_dt_ucode_base_size' symbol
  1158. try:
  1159. TestFunctional._MakeInputFile('u-boot',
  1160. tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
  1161. with self.assertRaises(ValueError) as e:
  1162. self._RunPackUbootSingleMicrocode()
  1163. self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
  1164. "_dt_ucode_base_size symbol in u-boot", str(e.exception))
  1165. finally:
  1166. # Put the original file back
  1167. TestFunctional._MakeInputFile('u-boot',
  1168. tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
  1169. def testMicrocodeNotInImage(self):
  1170. """Test that microcode must be placed within the image"""
  1171. with self.assertRaises(ValueError) as e:
  1172. self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
  1173. self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
  1174. "pointer _dt_ucode_base_size at fffffe14 is outside the "
  1175. "section ranging from 00000000 to 0000002e", str(e.exception))
  1176. def testWithoutMicrocode(self):
  1177. """Test that we can cope with an image without microcode (e.g. qemu)"""
  1178. TestFunctional._MakeInputFile('u-boot',
  1179. tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
  1180. data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
  1181. # Now check the device tree has no microcode
  1182. self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
  1183. second = data[len(U_BOOT_NODTB_DATA):]
  1184. fdt_len = self.GetFdtLen(second)
  1185. self.assertEqual(dtb, second[:fdt_len])
  1186. used_len = len(U_BOOT_NODTB_DATA) + fdt_len
  1187. third = data[used_len:]
  1188. self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
  1189. def testUnknownPosSize(self):
  1190. """Test that microcode must be placed within the image"""
  1191. with self.assertRaises(ValueError) as e:
  1192. self._DoReadFile('041_unknown_pos_size.dts', True)
  1193. self.assertIn("Section '/binman': Unable to set offset/size for unknown "
  1194. "entry 'invalid-entry'", str(e.exception))
  1195. def testPackFsp(self):
  1196. """Test that an image with a FSP binary can be created"""
  1197. data = self._DoReadFile('042_intel_fsp.dts')
  1198. self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
  1199. def testPackCmc(self):
  1200. """Test that an image with a CMC binary can be created"""
  1201. data = self._DoReadFile('043_intel_cmc.dts')
  1202. self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
  1203. def testPackVbt(self):
  1204. """Test that an image with a VBT binary can be created"""
  1205. data = self._DoReadFile('046_intel_vbt.dts')
  1206. self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
  1207. def testSplBssPad(self):
  1208. """Test that we can pad SPL's BSS with zeros"""
  1209. # ELF file with a '__bss_size' symbol
  1210. self._SetupSplElf()
  1211. data = self._DoReadFile('047_spl_bss_pad.dts')
  1212. self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
  1213. data)
  1214. def testSplBssPadMissing(self):
  1215. """Test that a missing symbol is detected"""
  1216. self._SetupSplElf('u_boot_ucode_ptr')
  1217. with self.assertRaises(ValueError) as e:
  1218. self._DoReadFile('047_spl_bss_pad.dts')
  1219. self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
  1220. str(e.exception))
  1221. def testPackStart16Spl(self):
  1222. """Test that an image with an x86 start16 SPL region can be created"""
  1223. data = self._DoReadFile('048_x86_start16_spl.dts')
  1224. self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
  1225. def _PackUbootSplMicrocode(self, dts, ucode_second=False):
  1226. """Helper function for microcode tests
  1227. We expect to see the following in the image, in order:
  1228. u-boot-spl-nodtb.bin with a microcode pointer inserted at the
  1229. correct place
  1230. u-boot.dtb with the microcode removed
  1231. the microcode
  1232. Args:
  1233. dts: Device tree file to use for test
  1234. ucode_second: True if the microsecond entry is second instead of
  1235. third
  1236. """
  1237. self._SetupSplElf('u_boot_ucode_ptr')
  1238. first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
  1239. ucode_second=ucode_second)
  1240. self.assertEqual(b'splnodtb with microc' + pos_and_size +
  1241. b'ter somewhere in here', first)
  1242. def testPackUbootSplMicrocode(self):
  1243. """Test that x86 microcode can be handled correctly in SPL"""
  1244. self._SetupSplElf()
  1245. self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
  1246. def testPackUbootSplMicrocodeReorder(self):
  1247. """Test that order doesn't matter for microcode entries
  1248. This is the same as testPackUbootSplMicrocode but when we process the
  1249. u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
  1250. entry, so we reply on binman to try later.
  1251. """
  1252. self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
  1253. ucode_second=True)
  1254. def testPackMrc(self):
  1255. """Test that an image with an MRC binary can be created"""
  1256. data = self._DoReadFile('050_intel_mrc.dts')
  1257. self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
  1258. def testSplDtb(self):
  1259. """Test that an image with spl/u-boot-spl.dtb can be created"""
  1260. self._SetupSplElf()
  1261. data = self._DoReadFile('051_u_boot_spl_dtb.dts')
  1262. self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
  1263. def testSplNoDtb(self):
  1264. """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
  1265. self._SetupSplElf()
  1266. data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
  1267. self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
  1268. def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
  1269. use_expanded=False, no_write_symbols=False):
  1270. """Check the image contains the expected symbol values
  1271. Args:
  1272. dts: Device tree file to use for test
  1273. base_data: Data before and after 'u-boot' section
  1274. u_boot_offset: Offset of 'u-boot' section in image
  1275. entry_args: Dict of entry args to supply to binman
  1276. key: arg name
  1277. value: value of that arg
  1278. use_expanded: True to use expanded entries where available, e.g.
  1279. 'u-boot-expanded' instead of 'u-boot'
  1280. """
  1281. elf_fname = self.ElfTestFile('u_boot_binman_syms')
  1282. syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
  1283. addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
  1284. self.assertEqual(syms['_binman_sym_magic'].address, addr)
  1285. self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
  1286. addr + 4)
  1287. self._SetupSplElf('u_boot_binman_syms')
  1288. data = self._DoReadFileDtb(dts, entry_args=entry_args,
  1289. use_expanded=use_expanded)[0]
  1290. # The image should contain the symbols from u_boot_binman_syms.c
  1291. # Note that image_pos is adjusted by the base address of the image,
  1292. # which is 0x10 in our test image
  1293. sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
  1294. 0x00, u_boot_offset + len(U_BOOT_DATA),
  1295. 0x10 + u_boot_offset, 0x04)
  1296. if no_write_symbols:
  1297. expected = (base_data +
  1298. tools.get_bytes(0xff, 0x38 - len(base_data)) +
  1299. U_BOOT_DATA + base_data)
  1300. else:
  1301. expected = (sym_values + base_data[24:] +
  1302. tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
  1303. base_data[24:])
  1304. self.assertEqual(expected, data)
  1305. def testSymbols(self):
  1306. """Test binman can assign symbols embedded in U-Boot"""
  1307. self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
  1308. def testSymbolsNoDtb(self):
  1309. """Test binman can assign symbols embedded in U-Boot SPL"""
  1310. self.checkSymbols('196_symbols_nodtb.dts',
  1311. U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
  1312. 0x38)
  1313. def testPackUnitAddress(self):
  1314. """Test that we support multiple binaries with the same name"""
  1315. data = self._DoReadFile('054_unit_address.dts')
  1316. self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
  1317. def testSections(self):
  1318. """Basic test of sections"""
  1319. data = self._DoReadFile('055_sections.dts')
  1320. expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
  1321. U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
  1322. U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
  1323. self.assertEqual(expected, data)
  1324. def testMap(self):
  1325. """Tests outputting a map of the images"""
  1326. _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
  1327. self.assertEqual('''ImagePos Offset Size Name
  1328. 00000000 00000000 00000028 image
  1329. 00000000 00000000 00000010 section@0
  1330. 00000000 00000000 00000004 u-boot
  1331. 00000010 00000010 00000010 section@1
  1332. 00000010 00000000 00000004 u-boot
  1333. 00000020 00000020 00000004 section@2
  1334. 00000020 00000000 00000004 u-boot
  1335. ''', map_data)
  1336. def testNamePrefix(self):
  1337. """Tests that name prefixes are used"""
  1338. _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
  1339. self.assertEqual('''ImagePos Offset Size Name
  1340. 00000000 00000000 00000028 image
  1341. 00000000 00000000 00000010 section@0
  1342. 00000000 00000000 00000004 ro-u-boot
  1343. 00000010 00000010 00000010 section@1
  1344. 00000010 00000000 00000004 rw-u-boot
  1345. ''', map_data)
  1346. def testUnknownContents(self):
  1347. """Test that obtaining the contents works as expected"""
  1348. with self.assertRaises(ValueError) as e:
  1349. self._DoReadFile('057_unknown_contents.dts', True)
  1350. self.assertIn("Image '/binman': Internal error: Could not complete "
  1351. "processing of contents: remaining ["
  1352. "<binman.etype._testing.Entry__testing ", str(e.exception))
  1353. def testBadChangeSize(self):
  1354. """Test that trying to change the size of an entry fails"""
  1355. try:
  1356. state.SetAllowEntryExpansion(False)
  1357. with self.assertRaises(ValueError) as e:
  1358. self._DoReadFile('059_change_size.dts', True)
  1359. self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
  1360. str(e.exception))
  1361. finally:
  1362. state.SetAllowEntryExpansion(True)
  1363. def testUpdateFdt(self):
  1364. """Test that we can update the device tree with offset/size info"""
  1365. _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
  1366. update_dtb=True)
  1367. dtb = fdt.Fdt(out_dtb_fname)
  1368. dtb.Scan()
  1369. props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
  1370. self.assertEqual({
  1371. 'image-pos': 0,
  1372. 'offset': 0,
  1373. '_testing:offset': 32,
  1374. '_testing:size': 2,
  1375. '_testing:image-pos': 32,
  1376. 'section@0/u-boot:offset': 0,
  1377. 'section@0/u-boot:size': len(U_BOOT_DATA),
  1378. 'section@0/u-boot:image-pos': 0,
  1379. 'section@0:offset': 0,
  1380. 'section@0:size': 16,
  1381. 'section@0:image-pos': 0,
  1382. 'section@1/u-boot:offset': 0,
  1383. 'section@1/u-boot:size': len(U_BOOT_DATA),
  1384. 'section@1/u-boot:image-pos': 16,
  1385. 'section@1:offset': 16,
  1386. 'section@1:size': 16,
  1387. 'section@1:image-pos': 16,
  1388. 'size': 40
  1389. }, props)
  1390. def testUpdateFdtBad(self):
  1391. """Test that we detect when ProcessFdt never completes"""
  1392. with self.assertRaises(ValueError) as e:
  1393. self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
  1394. self.assertIn('Could not complete processing of Fdt: remaining '
  1395. '[<binman.etype._testing.Entry__testing',
  1396. str(e.exception))
  1397. def testEntryArgs(self):
  1398. """Test passing arguments to entries from the command line"""
  1399. entry_args = {
  1400. 'test-str-arg': 'test1',
  1401. 'test-int-arg': '456',
  1402. }
  1403. self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
  1404. self.assertIn('image', control.images)
  1405. entry = control.images['image'].GetEntries()['_testing']
  1406. self.assertEqual('test0', entry.test_str_fdt)
  1407. self.assertEqual('test1', entry.test_str_arg)
  1408. self.assertEqual(123, entry.test_int_fdt)
  1409. self.assertEqual(456, entry.test_int_arg)
  1410. def testEntryArgsMissing(self):
  1411. """Test missing arguments and properties"""
  1412. entry_args = {
  1413. 'test-int-arg': '456',
  1414. }
  1415. self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
  1416. entry = control.images['image'].GetEntries()['_testing']
  1417. self.assertEqual('test0', entry.test_str_fdt)
  1418. self.assertEqual(None, entry.test_str_arg)
  1419. self.assertEqual(None, entry.test_int_fdt)
  1420. self.assertEqual(456, entry.test_int_arg)
  1421. def testEntryArgsRequired(self):
  1422. """Test missing arguments and properties"""
  1423. entry_args = {
  1424. 'test-int-arg': '456',
  1425. }
  1426. with self.assertRaises(ValueError) as e:
  1427. self._DoReadFileDtb('064_entry_args_required.dts')
  1428. self.assertIn("Node '/binman/_testing': "
  1429. 'Missing required properties/entry args: test-str-arg, '
  1430. 'test-int-fdt, test-int-arg',
  1431. str(e.exception))
  1432. def testEntryArgsInvalidFormat(self):
  1433. """Test that an invalid entry-argument format is detected"""
  1434. args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
  1435. '-ano-value']
  1436. with self.assertRaises(ValueError) as e:
  1437. self._DoBinman(*args)
  1438. self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
  1439. def testEntryArgsInvalidInteger(self):
  1440. """Test that an invalid entry-argument integer is detected"""
  1441. entry_args = {
  1442. 'test-int-arg': 'abc',
  1443. }
  1444. with self.assertRaises(ValueError) as e:
  1445. self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
  1446. self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
  1447. "'test-int-arg' (value 'abc') to integer",
  1448. str(e.exception))
  1449. def testEntryArgsInvalidDatatype(self):
  1450. """Test that an invalid entry-argument datatype is detected
  1451. This test could be written in entry_test.py except that it needs
  1452. access to control.entry_args, which seems more than that module should
  1453. be able to see.
  1454. """
  1455. entry_args = {
  1456. 'test-bad-datatype-arg': '12',
  1457. }
  1458. with self.assertRaises(ValueError) as e:
  1459. self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
  1460. entry_args=entry_args)
  1461. self.assertIn('GetArg() internal error: Unknown data type ',
  1462. str(e.exception))
  1463. def testText(self):
  1464. """Test for a text entry type"""
  1465. entry_args = {
  1466. 'test-id': TEXT_DATA,
  1467. 'test-id2': TEXT_DATA2,
  1468. 'test-id3': TEXT_DATA3,
  1469. }
  1470. data, _, _, _ = self._DoReadFileDtb('066_text.dts',
  1471. entry_args=entry_args)
  1472. expected = (tools.to_bytes(TEXT_DATA) +
  1473. tools.get_bytes(0, 8 - len(TEXT_DATA)) +
  1474. tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
  1475. b'some text' + b'more text')
  1476. self.assertEqual(expected, data)
  1477. def testEntryDocs(self):
  1478. """Test for creation of entry documentation"""
  1479. with test_util.capture_sys_output() as (stdout, stderr):
  1480. control.WriteEntryDocs(control.GetEntryModules())
  1481. self.assertTrue(len(stdout.getvalue()) > 0)
  1482. def testEntryDocsMissing(self):
  1483. """Test handling of missing entry documentation"""
  1484. with self.assertRaises(ValueError) as e:
  1485. with test_util.capture_sys_output() as (stdout, stderr):
  1486. control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
  1487. self.assertIn('Documentation is missing for modules: u_boot',
  1488. str(e.exception))
  1489. def testFmap(self):
  1490. """Basic test of generation of a flashrom fmap"""
  1491. data = self._DoReadFile('067_fmap.dts')
  1492. fhdr, fentries = fmap_util.DecodeFmap(data[32:])
  1493. expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
  1494. U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
  1495. self.assertEqual(expected, data[:32])
  1496. self.assertEqual(b'__FMAP__', fhdr.signature)
  1497. self.assertEqual(1, fhdr.ver_major)
  1498. self.assertEqual(0, fhdr.ver_minor)
  1499. self.assertEqual(0, fhdr.base)
  1500. expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
  1501. self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
  1502. self.assertEqual(b'FMAP', fhdr.name)
  1503. self.assertEqual(5, fhdr.nareas)
  1504. fiter = iter(fentries)
  1505. fentry = next(fiter)
  1506. self.assertEqual(b'SECTION0', fentry.name)
  1507. self.assertEqual(0, fentry.offset)
  1508. self.assertEqual(16, fentry.size)
  1509. self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
  1510. fentry = next(fiter)
  1511. self.assertEqual(b'RO_U_BOOT', fentry.name)
  1512. self.assertEqual(0, fentry.offset)
  1513. self.assertEqual(4, fentry.size)
  1514. self.assertEqual(0, fentry.flags)
  1515. fentry = next(fiter)
  1516. self.assertEqual(b'SECTION1', fentry.name)
  1517. self.assertEqual(16, fentry.offset)
  1518. self.assertEqual(16, fentry.size)
  1519. self.assertEqual(0, fentry.flags)
  1520. fentry = next(fiter)
  1521. self.assertEqual(b'RW_U_BOOT', fentry.name)
  1522. self.assertEqual(16, fentry.offset)
  1523. self.assertEqual(4, fentry.size)
  1524. self.assertEqual(0, fentry.flags)
  1525. fentry = next(fiter)
  1526. self.assertEqual(b'FMAP', fentry.name)
  1527. self.assertEqual(32, fentry.offset)
  1528. self.assertEqual(expect_size, fentry.size)
  1529. self.assertEqual(0, fentry.flags)
  1530. def testBlobNamedByArg(self):
  1531. """Test we can add a blob with the filename coming from an entry arg"""
  1532. entry_args = {
  1533. 'cros-ec-rw-path': 'ecrw.bin',
  1534. }
  1535. self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
  1536. def testFill(self):
  1537. """Test for an fill entry type"""
  1538. data = self._DoReadFile('069_fill.dts')
  1539. expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
  1540. self.assertEqual(expected, data)
  1541. def testFillNoSize(self):
  1542. """Test for an fill entry type with no size"""
  1543. with self.assertRaises(ValueError) as e:
  1544. self._DoReadFile('070_fill_no_size.dts')
  1545. self.assertIn("'fill' entry is missing properties: size",
  1546. str(e.exception))
  1547. def _HandleGbbCommand(self, pipe_list):
  1548. """Fake calls to the futility utility"""
  1549. if 'futility' in pipe_list[0][0]:
  1550. fname = pipe_list[0][-1]
  1551. # Append our GBB data to the file, which will happen every time the
  1552. # futility command is called.
  1553. with open(fname, 'ab') as fd:
  1554. fd.write(GBB_DATA)
  1555. return command.CommandResult()
  1556. def testGbb(self):
  1557. """Test for the Chromium OS Google Binary Block"""
  1558. command.test_result = self._HandleGbbCommand
  1559. entry_args = {
  1560. 'keydir': 'devkeys',
  1561. 'bmpblk': 'bmpblk.bin',
  1562. }
  1563. data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
  1564. # Since futility
  1565. expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
  1566. tools.get_bytes(0, 0x2180 - 16))
  1567. self.assertEqual(expected, data)
  1568. def testGbbTooSmall(self):
  1569. """Test for the Chromium OS Google Binary Block being large enough"""
  1570. with self.assertRaises(ValueError) as e:
  1571. self._DoReadFileDtb('072_gbb_too_small.dts')
  1572. self.assertIn("Node '/binman/gbb': GBB is too small",
  1573. str(e.exception))
  1574. def testGbbNoSize(self):
  1575. """Test for the Chromium OS Google Binary Block having a size"""
  1576. with self.assertRaises(ValueError) as e:
  1577. self._DoReadFileDtb('073_gbb_no_size.dts')
  1578. self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
  1579. str(e.exception))
  1580. def testGbbMissing(self):
  1581. """Test that binman still produces an image if futility is missing"""
  1582. entry_args = {
  1583. 'keydir': 'devkeys',
  1584. }
  1585. with test_util.capture_sys_output() as (_, stderr):
  1586. self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
  1587. entry_args=entry_args)
  1588. err = stderr.getvalue()
  1589. self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
  1590. def _HandleVblockCommand(self, pipe_list):
  1591. """Fake calls to the futility utility
  1592. The expected pipe is:
  1593. [('futility', 'vbutil_firmware', '--vblock',
  1594. 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
  1595. '--signprivate', 'devkeys/firmware_data_key.vbprivk',
  1596. '--version', '1', '--fv', 'input.vblock', '--kernelkey',
  1597. 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
  1598. This writes to the output file (here, 'vblock.vblock'). If
  1599. self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
  1600. of the input data (here, 'input.vblock').
  1601. """
  1602. if 'futility' in pipe_list[0][0]:
  1603. fname = pipe_list[0][3]
  1604. with open(fname, 'wb') as fd:
  1605. if self._hash_data:
  1606. infile = pipe_list[0][11]
  1607. m = hashlib.sha256()
  1608. data = tools.read_file(infile)
  1609. m.update(data)
  1610. fd.write(m.digest())
  1611. else:
  1612. fd.write(VBLOCK_DATA)
  1613. return command.CommandResult()
  1614. def testVblock(self):
  1615. """Test for the Chromium OS Verified Boot Block"""
  1616. self._hash_data = False
  1617. command.test_result = self._HandleVblockCommand
  1618. entry_args = {
  1619. 'keydir': 'devkeys',
  1620. }
  1621. data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
  1622. entry_args=entry_args)
  1623. expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
  1624. self.assertEqual(expected, data)
  1625. def testVblockNoContent(self):
  1626. """Test we detect a vblock which has no content to sign"""
  1627. with self.assertRaises(ValueError) as e:
  1628. self._DoReadFile('075_vblock_no_content.dts')
  1629. self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
  1630. 'property', str(e.exception))
  1631. def testVblockBadPhandle(self):
  1632. """Test that we detect a vblock with an invalid phandle in contents"""
  1633. with self.assertRaises(ValueError) as e:
  1634. self._DoReadFile('076_vblock_bad_phandle.dts')
  1635. self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
  1636. '1000', str(e.exception))
  1637. def testVblockBadEntry(self):
  1638. """Test that we detect an entry that points to a non-entry"""
  1639. with self.assertRaises(ValueError) as e:
  1640. self._DoReadFile('077_vblock_bad_entry.dts')
  1641. self.assertIn("Node '/binman/vblock': Cannot find entry for node "
  1642. "'other'", str(e.exception))
  1643. def testVblockContent(self):
  1644. """Test that the vblock signs the right data"""
  1645. self._hash_data = True
  1646. command.test_result = self._HandleVblockCommand
  1647. entry_args = {
  1648. 'keydir': 'devkeys',
  1649. }
  1650. data = self._DoReadFileDtb(
  1651. '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
  1652. entry_args=entry_args)[0]
  1653. hashlen = 32 # SHA256 hash is 32 bytes
  1654. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  1655. hashval = data[-hashlen:]
  1656. dtb = data[len(U_BOOT_DATA):-hashlen]
  1657. expected_data = U_BOOT_DATA + dtb
  1658. # The hashval should be a hash of the dtb
  1659. m = hashlib.sha256()
  1660. m.update(expected_data)
  1661. expected_hashval = m.digest()
  1662. self.assertEqual(expected_hashval, hashval)
  1663. def testVblockMissing(self):
  1664. """Test that binman still produces an image if futility is missing"""
  1665. entry_args = {
  1666. 'keydir': 'devkeys',
  1667. }
  1668. with test_util.capture_sys_output() as (_, stderr):
  1669. self._DoTestFile('074_vblock.dts',
  1670. force_missing_bintools='futility',
  1671. entry_args=entry_args)
  1672. err = stderr.getvalue()
  1673. self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
  1674. def testTpl(self):
  1675. """Test that an image with TPL and its device tree can be created"""
  1676. # ELF file with a '__bss_size' symbol
  1677. self._SetupTplElf()
  1678. data = self._DoReadFile('078_u_boot_tpl.dts')
  1679. self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
  1680. def testUsesPos(self):
  1681. """Test that the 'pos' property cannot be used anymore"""
  1682. with self.assertRaises(ValueError) as e:
  1683. data = self._DoReadFile('079_uses_pos.dts')
  1684. self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
  1685. "'pos'", str(e.exception))
  1686. def testFillZero(self):
  1687. """Test for an fill entry type with a size of 0"""
  1688. data = self._DoReadFile('080_fill_empty.dts')
  1689. self.assertEqual(tools.get_bytes(0, 16), data)
  1690. def testTextMissing(self):
  1691. """Test for a text entry type where there is no text"""
  1692. with self.assertRaises(ValueError) as e:
  1693. self._DoReadFileDtb('066_text.dts',)
  1694. self.assertIn("Node '/binman/text': No value provided for text label "
  1695. "'test-id'", str(e.exception))
  1696. def testPackStart16Tpl(self):
  1697. """Test that an image with an x86 start16 TPL region can be created"""
  1698. data = self._DoReadFile('081_x86_start16_tpl.dts')
  1699. self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
  1700. def testSelectImage(self):
  1701. """Test that we can select which images to build"""
  1702. expected = 'Skipping images: image1'
  1703. # We should only get the expected message in verbose mode
  1704. for verbosity in (0, 2):
  1705. with test_util.capture_sys_output() as (stdout, stderr):
  1706. retcode = self._DoTestFile('006_dual_image.dts',
  1707. verbosity=verbosity,
  1708. images=['image2'])
  1709. self.assertEqual(0, retcode)
  1710. if verbosity:
  1711. self.assertIn(expected, stdout.getvalue())
  1712. else:
  1713. self.assertNotIn(expected, stdout.getvalue())
  1714. self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
  1715. self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
  1716. self._CleanupOutputDir()
  1717. def testUpdateFdtAll(self):
  1718. """Test that all device trees are updated with offset/size info"""
  1719. self._SetupSplElf()
  1720. self._SetupTplElf()
  1721. data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
  1722. base_expected = {
  1723. 'offset': 0,
  1724. 'image-pos': 0,
  1725. 'size': 2320,
  1726. 'section:offset': 0,
  1727. 'section:image-pos': 0,
  1728. 'section:size': 565,
  1729. 'section/u-boot-dtb:offset': 0,
  1730. 'section/u-boot-dtb:image-pos': 0,
  1731. 'section/u-boot-dtb:size': 565,
  1732. 'u-boot-spl-dtb:offset': 565,
  1733. 'u-boot-spl-dtb:image-pos': 565,
  1734. 'u-boot-spl-dtb:size': 585,
  1735. 'u-boot-tpl-dtb:offset': 1150,
  1736. 'u-boot-tpl-dtb:image-pos': 1150,
  1737. 'u-boot-tpl-dtb:size': 585,
  1738. 'u-boot-vpl-dtb:image-pos': 1735,
  1739. 'u-boot-vpl-dtb:offset': 1735,
  1740. 'u-boot-vpl-dtb:size': 585,
  1741. }
  1742. # We expect three device-tree files in the output, one after the other.
  1743. # Read them in sequence. We look for an 'spl' property in the SPL tree,
  1744. # and 'tpl' in the TPL tree, to make sure they are distinct from the
  1745. # main U-Boot tree. All three should have the same postions and offset.
  1746. start = 0
  1747. self.maxDiff = None
  1748. for item in ['', 'spl', 'tpl', 'vpl']:
  1749. dtb = fdt.Fdt.FromData(data[start:])
  1750. dtb.Scan()
  1751. props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
  1752. ['spl', 'tpl', 'vpl'])
  1753. expected = dict(base_expected)
  1754. if item:
  1755. expected[item] = 0
  1756. self.assertEqual(expected, props)
  1757. start += dtb._fdt_obj.totalsize()
  1758. def testUpdateFdtOutput(self):
  1759. """Test that output DTB files are updated"""
  1760. try:
  1761. data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
  1762. use_real_dtb=True, update_dtb=True, reset_dtbs=False)
  1763. # Unfortunately, compiling a source file always results in a file
  1764. # called source.dtb (see fdt_util.EnsureCompiled()). The test
  1765. # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
  1766. # binman as a file called u-boot.dtb. To fix this, copy the file
  1767. # over to the expected place.
  1768. start = 0
  1769. for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
  1770. 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
  1771. dtb = fdt.Fdt.FromData(data[start:])
  1772. size = dtb._fdt_obj.totalsize()
  1773. pathname = tools.get_output_filename(os.path.split(fname)[1])
  1774. outdata = tools.read_file(pathname)
  1775. name = os.path.split(fname)[0]
  1776. if name:
  1777. orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
  1778. else:
  1779. orig_indata = dtb_data
  1780. self.assertNotEqual(outdata, orig_indata,
  1781. "Expected output file '%s' be updated" % pathname)
  1782. self.assertEqual(outdata, data[start:start + size],
  1783. "Expected output file '%s' to match output image" %
  1784. pathname)
  1785. start += size
  1786. finally:
  1787. self._ResetDtbs()
  1788. def _decompress(self, data):
  1789. bintool = self.comp_bintools['lz4']
  1790. return bintool.decompress(data)
  1791. def testCompress(self):
  1792. """Test compression of blobs"""
  1793. self._CheckLz4()
  1794. data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
  1795. use_real_dtb=True, update_dtb=True)
  1796. dtb = fdt.Fdt(out_dtb_fname)
  1797. dtb.Scan()
  1798. props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
  1799. orig = self._decompress(data)
  1800. self.assertEquals(COMPRESS_DATA, orig)
  1801. # Do a sanity check on various fields
  1802. image = control.images['image']
  1803. entries = image.GetEntries()
  1804. self.assertEqual(1, len(entries))
  1805. entry = entries['blob']
  1806. self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
  1807. self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
  1808. orig = self._decompress(entry.data)
  1809. self.assertEqual(orig, entry.uncomp_data)
  1810. self.assertEqual(image.data, entry.data)
  1811. expected = {
  1812. 'blob:uncomp-size': len(COMPRESS_DATA),
  1813. 'blob:size': len(data),
  1814. 'size': len(data),
  1815. }
  1816. self.assertEqual(expected, props)
  1817. def testFiles(self):
  1818. """Test bringing in multiple files"""
  1819. data = self._DoReadFile('084_files.dts')
  1820. self.assertEqual(FILES_DATA, data)
  1821. def testFilesCompress(self):
  1822. """Test bringing in multiple files and compressing them"""
  1823. self._CheckLz4()
  1824. data = self._DoReadFile('085_files_compress.dts')
  1825. image = control.images['image']
  1826. entries = image.GetEntries()
  1827. files = entries['files']
  1828. entries = files._entries
  1829. orig = b''
  1830. for i in range(1, 3):
  1831. key = '%d.dat' % i
  1832. start = entries[key].image_pos
  1833. len = entries[key].size
  1834. chunk = data[start:start + len]
  1835. orig += self._decompress(chunk)
  1836. self.assertEqual(FILES_DATA, orig)
  1837. def testFilesMissing(self):
  1838. """Test missing files"""
  1839. with self.assertRaises(ValueError) as e:
  1840. data = self._DoReadFile('086_files_none.dts')
  1841. self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
  1842. 'no files', str(e.exception))
  1843. def testFilesNoPattern(self):
  1844. """Test missing files"""
  1845. with self.assertRaises(ValueError) as e:
  1846. data = self._DoReadFile('087_files_no_pattern.dts')
  1847. self.assertIn("Node '/binman/files': Missing 'pattern' property",
  1848. str(e.exception))
  1849. def testExtendSize(self):
  1850. """Test an extending entry"""
  1851. data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
  1852. map=True)
  1853. expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
  1854. MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
  1855. tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
  1856. tools.get_bytes(ord('d'), 8))
  1857. self.assertEqual(expect, data)
  1858. self.assertEqual('''ImagePos Offset Size Name
  1859. 00000000 00000000 00000028 image
  1860. 00000000 00000000 00000008 fill
  1861. 00000008 00000008 00000004 u-boot
  1862. 0000000c 0000000c 00000004 section
  1863. 0000000c 00000000 00000003 intel-mrc
  1864. 00000010 00000010 00000004 u-boot2
  1865. 00000014 00000014 0000000c section2
  1866. 00000014 00000000 00000008 fill
  1867. 0000001c 00000008 00000004 u-boot
  1868. 00000020 00000020 00000008 fill2
  1869. ''', map_data)
  1870. def testExtendSizeBad(self):
  1871. """Test an extending entry which fails to provide contents"""
  1872. with test_util.capture_sys_output() as (stdout, stderr):
  1873. with self.assertRaises(ValueError) as e:
  1874. self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
  1875. self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
  1876. 'expanding entry', str(e.exception))
  1877. def testHash(self):
  1878. """Test hashing of the contents of an entry"""
  1879. _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
  1880. use_real_dtb=True, update_dtb=True)
  1881. dtb = fdt.Fdt(out_dtb_fname)
  1882. dtb.Scan()
  1883. hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
  1884. m = hashlib.sha256()
  1885. m.update(U_BOOT_DATA)
  1886. self.assertEqual(m.digest(), b''.join(hash_node.value))
  1887. def testHashNoAlgo(self):
  1888. with self.assertRaises(ValueError) as e:
  1889. self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
  1890. self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
  1891. 'hash node', str(e.exception))
  1892. def testHashBadAlgo(self):
  1893. with self.assertRaises(ValueError) as e:
  1894. self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
  1895. self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
  1896. str(e.exception))
  1897. def testHashSection(self):
  1898. """Test hashing of the contents of an entry"""
  1899. _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
  1900. use_real_dtb=True, update_dtb=True)
  1901. dtb = fdt.Fdt(out_dtb_fname)
  1902. dtb.Scan()
  1903. hash_node = dtb.GetNode('/binman/section/hash').props['value']
  1904. m = hashlib.sha256()
  1905. m.update(U_BOOT_DATA)
  1906. m.update(tools.get_bytes(ord('a'), 16))
  1907. self.assertEqual(m.digest(), b''.join(hash_node.value))
  1908. def testPackUBootTplMicrocode(self):
  1909. """Test that x86 microcode can be handled correctly in TPL
  1910. We expect to see the following in the image, in order:
  1911. u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
  1912. place
  1913. u-boot-tpl.dtb with the microcode removed
  1914. the microcode
  1915. """
  1916. self._SetupTplElf('u_boot_ucode_ptr')
  1917. first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
  1918. U_BOOT_TPL_NODTB_DATA)
  1919. self.assertEqual(b'tplnodtb with microc' + pos_and_size +
  1920. b'ter somewhere in here', first)
  1921. def testFmapX86(self):
  1922. """Basic test of generation of a flashrom fmap"""
  1923. data = self._DoReadFile('094_fmap_x86.dts')
  1924. fhdr, fentries = fmap_util.DecodeFmap(data[32:])
  1925. expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
  1926. self.assertEqual(expected, data[:32])
  1927. fhdr, fentries = fmap_util.DecodeFmap(data[32:])
  1928. self.assertEqual(0x100, fhdr.image_size)
  1929. self.assertEqual(0, fentries[0].offset)
  1930. self.assertEqual(4, fentries[0].size)
  1931. self.assertEqual(b'U_BOOT', fentries[0].name)
  1932. self.assertEqual(4, fentries[1].offset)
  1933. self.assertEqual(3, fentries[1].size)
  1934. self.assertEqual(b'INTEL_MRC', fentries[1].name)
  1935. self.assertEqual(32, fentries[2].offset)
  1936. self.assertEqual(fmap_util.FMAP_HEADER_LEN +
  1937. fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
  1938. self.assertEqual(b'FMAP', fentries[2].name)
  1939. def testFmapX86Section(self):
  1940. """Basic test of generation of a flashrom fmap"""
  1941. data = self._DoReadFile('095_fmap_x86_section.dts')
  1942. expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
  1943. self.assertEqual(expected, data[:32])
  1944. fhdr, fentries = fmap_util.DecodeFmap(data[36:])
  1945. self.assertEqual(0x180, fhdr.image_size)
  1946. expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
  1947. fiter = iter(fentries)
  1948. fentry = next(fiter)
  1949. self.assertEqual(b'U_BOOT', fentry.name)
  1950. self.assertEqual(0, fentry.offset)
  1951. self.assertEqual(4, fentry.size)
  1952. fentry = next(fiter)
  1953. self.assertEqual(b'SECTION', fentry.name)
  1954. self.assertEqual(4, fentry.offset)
  1955. self.assertEqual(0x20 + expect_size, fentry.size)
  1956. fentry = next(fiter)
  1957. self.assertEqual(b'INTEL_MRC', fentry.name)
  1958. self.assertEqual(4, fentry.offset)
  1959. self.assertEqual(3, fentry.size)
  1960. fentry = next(fiter)
  1961. self.assertEqual(b'FMAP', fentry.name)
  1962. self.assertEqual(36, fentry.offset)
  1963. self.assertEqual(expect_size, fentry.size)
  1964. def testElf(self):
  1965. """Basic test of ELF entries"""
  1966. self._SetupSplElf()
  1967. self._SetupTplElf()
  1968. with open(self.ElfTestFile('bss_data'), 'rb') as fd:
  1969. TestFunctional._MakeInputFile('-boot', fd.read())
  1970. data = self._DoReadFile('096_elf.dts')
  1971. def testElfStrip(self):
  1972. """Basic test of ELF entries"""
  1973. self._SetupSplElf()
  1974. with open(self.ElfTestFile('bss_data'), 'rb') as fd:
  1975. TestFunctional._MakeInputFile('-boot', fd.read())
  1976. data = self._DoReadFile('097_elf_strip.dts')
  1977. def testPackOverlapMap(self):
  1978. """Test that overlapping regions are detected"""
  1979. with test_util.capture_sys_output() as (stdout, stderr):
  1980. with self.assertRaises(ValueError) as e:
  1981. self._DoTestFile('014_pack_overlap.dts', map=True)
  1982. map_fname = tools.get_output_filename('image.map')
  1983. self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
  1984. stdout.getvalue())
  1985. # We should not get an inmage, but there should be a map file
  1986. self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
  1987. self.assertTrue(os.path.exists(map_fname))
  1988. map_data = tools.read_file(map_fname, binary=False)
  1989. self.assertEqual('''ImagePos Offset Size Name
  1990. <none> 00000000 00000008 image
  1991. <none> 00000000 00000004 u-boot
  1992. <none> 00000003 00000004 u-boot-align
  1993. ''', map_data)
  1994. def testPackRefCode(self):
  1995. """Test that an image with an Intel Reference code binary works"""
  1996. data = self._DoReadFile('100_intel_refcode.dts')
  1997. self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
  1998. def testSectionOffset(self):
  1999. """Tests use of a section with an offset"""
  2000. data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
  2001. map=True)
  2002. self.assertEqual('''ImagePos Offset Size Name
  2003. 00000000 00000000 00000038 image
  2004. 00000004 00000004 00000010 section@0
  2005. 00000004 00000000 00000004 u-boot
  2006. 00000018 00000018 00000010 section@1
  2007. 00000018 00000000 00000004 u-boot
  2008. 0000002c 0000002c 00000004 section@2
  2009. 0000002c 00000000 00000004 u-boot
  2010. ''', map_data)
  2011. self.assertEqual(data,
  2012. tools.get_bytes(0x26, 4) + U_BOOT_DATA +
  2013. tools.get_bytes(0x21, 12) +
  2014. tools.get_bytes(0x26, 4) + U_BOOT_DATA +
  2015. tools.get_bytes(0x61, 12) +
  2016. tools.get_bytes(0x26, 4) + U_BOOT_DATA +
  2017. tools.get_bytes(0x26, 8))
  2018. def testCbfsRaw(self):
  2019. """Test base handling of a Coreboot Filesystem (CBFS)
  2020. The exact contents of the CBFS is verified by similar tests in
  2021. cbfs_util_test.py. The tests here merely check that the files added to
  2022. the CBFS can be found in the final image.
  2023. """
  2024. data = self._DoReadFile('102_cbfs_raw.dts')
  2025. size = 0xb0
  2026. cbfs = cbfs_util.CbfsReader(data)
  2027. self.assertEqual(size, cbfs.rom_size)
  2028. self.assertIn('u-boot-dtb', cbfs.files)
  2029. cfile = cbfs.files['u-boot-dtb']
  2030. self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
  2031. def testCbfsArch(self):
  2032. """Test on non-x86 architecture"""
  2033. data = self._DoReadFile('103_cbfs_raw_ppc.dts')
  2034. size = 0x100
  2035. cbfs = cbfs_util.CbfsReader(data)
  2036. self.assertEqual(size, cbfs.rom_size)
  2037. self.assertIn('u-boot-dtb', cbfs.files)
  2038. cfile = cbfs.files['u-boot-dtb']
  2039. self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
  2040. def testCbfsStage(self):
  2041. """Tests handling of a Coreboot Filesystem (CBFS)"""
  2042. if not elf.ELF_TOOLS:
  2043. self.skipTest('Python elftools not available')
  2044. elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
  2045. elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
  2046. size = 0xb0
  2047. data = self._DoReadFile('104_cbfs_stage.dts')
  2048. cbfs = cbfs_util.CbfsReader(data)
  2049. self.assertEqual(size, cbfs.rom_size)
  2050. self.assertIn('u-boot', cbfs.files)
  2051. cfile = cbfs.files['u-boot']
  2052. self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
  2053. def testCbfsRawCompress(self):
  2054. """Test handling of compressing raw files"""
  2055. self._CheckLz4()
  2056. data = self._DoReadFile('105_cbfs_raw_compress.dts')
  2057. size = 0x140
  2058. cbfs = cbfs_util.CbfsReader(data)
  2059. self.assertIn('u-boot', cbfs.files)
  2060. cfile = cbfs.files['u-boot']
  2061. self.assertEqual(COMPRESS_DATA, cfile.data)
  2062. def testCbfsBadArch(self):
  2063. """Test handling of a bad architecture"""
  2064. with self.assertRaises(ValueError) as e:
  2065. self._DoReadFile('106_cbfs_bad_arch.dts')
  2066. self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
  2067. def testCbfsNoSize(self):
  2068. """Test handling of a missing size property"""
  2069. with self.assertRaises(ValueError) as e:
  2070. self._DoReadFile('107_cbfs_no_size.dts')
  2071. self.assertIn('entry must have a size property', str(e.exception))
  2072. def testCbfsNoContents(self):
  2073. """Test handling of a CBFS entry which does not provide contentsy"""
  2074. with self.assertRaises(ValueError) as e:
  2075. self._DoReadFile('108_cbfs_no_contents.dts')
  2076. self.assertIn('Could not complete processing of contents',
  2077. str(e.exception))
  2078. def testCbfsBadCompress(self):
  2079. """Test handling of a bad architecture"""
  2080. with self.assertRaises(ValueError) as e:
  2081. self._DoReadFile('109_cbfs_bad_compress.dts')
  2082. self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
  2083. str(e.exception))
  2084. def testCbfsNamedEntries(self):
  2085. """Test handling of named entries"""
  2086. data = self._DoReadFile('110_cbfs_name.dts')
  2087. cbfs = cbfs_util.CbfsReader(data)
  2088. self.assertIn('FRED', cbfs.files)
  2089. cfile1 = cbfs.files['FRED']
  2090. self.assertEqual(U_BOOT_DATA, cfile1.data)
  2091. self.assertIn('hello', cbfs.files)
  2092. cfile2 = cbfs.files['hello']
  2093. self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
  2094. def _SetupIfwi(self, fname):
  2095. """Set up to run an IFWI test
  2096. Args:
  2097. fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
  2098. """
  2099. self._SetupSplElf()
  2100. self._SetupTplElf()
  2101. # Intel Integrated Firmware Image (IFWI) file
  2102. with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
  2103. data = fd.read()
  2104. TestFunctional._MakeInputFile(fname,data)
  2105. def _CheckIfwi(self, data):
  2106. """Check that an image with an IFWI contains the correct output
  2107. Args:
  2108. data: Conents of output file
  2109. """
  2110. expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
  2111. if data[:0x1000] != expected_desc:
  2112. self.fail('Expected descriptor binary at start of image')
  2113. # We expect to find the TPL wil in subpart IBBP entry IBBL
  2114. image_fname = tools.get_output_filename('image.bin')
  2115. tpl_fname = tools.get_output_filename('tpl.out')
  2116. ifwitool = bintool.Bintool.create('ifwitool')
  2117. ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
  2118. tpl_data = tools.read_file(tpl_fname)
  2119. self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
  2120. def testPackX86RomIfwi(self):
  2121. """Test that an x86 ROM with Integrated Firmware Image can be created"""
  2122. self._SetupIfwi('fitimage.bin')
  2123. data = self._DoReadFile('111_x86_rom_ifwi.dts')
  2124. self._CheckIfwi(data)
  2125. def testPackX86RomIfwiNoDesc(self):
  2126. """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
  2127. self._SetupIfwi('ifwi.bin')
  2128. data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
  2129. self._CheckIfwi(data)
  2130. def testPackX86RomIfwiNoData(self):
  2131. """Test that an x86 ROM with IFWI handles missing data"""
  2132. self._SetupIfwi('ifwi.bin')
  2133. with self.assertRaises(ValueError) as e:
  2134. data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
  2135. self.assertIn('Could not complete processing of contents',
  2136. str(e.exception))
  2137. def testIfwiMissing(self):
  2138. """Test that binman still produces an image if ifwitool is missing"""
  2139. self._SetupIfwi('fitimage.bin')
  2140. with test_util.capture_sys_output() as (_, stderr):
  2141. self._DoTestFile('111_x86_rom_ifwi.dts',
  2142. force_missing_bintools='ifwitool')
  2143. err = stderr.getvalue()
  2144. self.assertRegex(err,
  2145. "Image 'image'.*missing bintools.*: ifwitool")
  2146. def testCbfsOffset(self):
  2147. """Test a CBFS with files at particular offsets
  2148. Like all CFBS tests, this is just checking the logic that calls
  2149. cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
  2150. """
  2151. data = self._DoReadFile('114_cbfs_offset.dts')
  2152. size = 0x200
  2153. cbfs = cbfs_util.CbfsReader(data)
  2154. self.assertEqual(size, cbfs.rom_size)
  2155. self.assertIn('u-boot', cbfs.files)
  2156. cfile = cbfs.files['u-boot']
  2157. self.assertEqual(U_BOOT_DATA, cfile.data)
  2158. self.assertEqual(0x40, cfile.cbfs_offset)
  2159. self.assertIn('u-boot-dtb', cbfs.files)
  2160. cfile2 = cbfs.files['u-boot-dtb']
  2161. self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
  2162. self.assertEqual(0x140, cfile2.cbfs_offset)
  2163. def testFdtmap(self):
  2164. """Test an FDT map can be inserted in the image"""
  2165. data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
  2166. fdtmap_data = data[len(U_BOOT_DATA):]
  2167. magic = fdtmap_data[:8]
  2168. self.assertEqual(b'_FDTMAP_', magic)
  2169. self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
  2170. fdt_data = fdtmap_data[16:]
  2171. dtb = fdt.Fdt.FromData(fdt_data)
  2172. dtb.Scan()
  2173. props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
  2174. self.assertEqual({
  2175. 'image-pos': 0,
  2176. 'offset': 0,
  2177. 'u-boot:offset': 0,
  2178. 'u-boot:size': len(U_BOOT_DATA),
  2179. 'u-boot:image-pos': 0,
  2180. 'fdtmap:image-pos': 4,
  2181. 'fdtmap:offset': 4,
  2182. 'fdtmap:size': len(fdtmap_data),
  2183. 'size': len(data),
  2184. }, props)
  2185. def testFdtmapNoMatch(self):
  2186. """Check handling of an FDT map when the section cannot be found"""
  2187. self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
  2188. # Mangle the section name, which should cause a mismatch between the
  2189. # correct FDT path and the one expected by the section
  2190. image = control.images['image']
  2191. image._node.path += '-suffix'
  2192. entries = image.GetEntries()
  2193. fdtmap = entries['fdtmap']
  2194. with self.assertRaises(ValueError) as e:
  2195. fdtmap._GetFdtmap()
  2196. self.assertIn("Cannot locate node for path '/binman-suffix'",
  2197. str(e.exception))
  2198. def testFdtmapHeader(self):
  2199. """Test an FDT map and image header can be inserted in the image"""
  2200. data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
  2201. fdtmap_pos = len(U_BOOT_DATA)
  2202. fdtmap_data = data[fdtmap_pos:]
  2203. fdt_data = fdtmap_data[16:]
  2204. dtb = fdt.Fdt.FromData(fdt_data)
  2205. fdt_size = dtb.GetFdtObj().totalsize()
  2206. hdr_data = data[-8:]
  2207. self.assertEqual(b'BinM', hdr_data[:4])
  2208. offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
  2209. self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
  2210. def testFdtmapHeaderStart(self):
  2211. """Test an image header can be inserted at the image start"""
  2212. data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
  2213. fdtmap_pos = 0x100 + len(U_BOOT_DATA)
  2214. hdr_data = data[:8]
  2215. self.assertEqual(b'BinM', hdr_data[:4])
  2216. offset = struct.unpack('<I', hdr_data[4:])[0]
  2217. self.assertEqual(fdtmap_pos, offset)
  2218. def testFdtmapHeaderPos(self):
  2219. """Test an image header can be inserted at a chosen position"""
  2220. data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
  2221. fdtmap_pos = 0x100 + len(U_BOOT_DATA)
  2222. hdr_data = data[0x80:0x88]
  2223. self.assertEqual(b'BinM', hdr_data[:4])
  2224. offset = struct.unpack('<I', hdr_data[4:])[0]
  2225. self.assertEqual(fdtmap_pos, offset)
  2226. def testHeaderMissingFdtmap(self):
  2227. """Test an image header requires an fdtmap"""
  2228. with self.assertRaises(ValueError) as e:
  2229. self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
  2230. self.assertIn("'image_header' section must have an 'fdtmap' sibling",
  2231. str(e.exception))
  2232. def testHeaderNoLocation(self):
  2233. """Test an image header with a no specified location is detected"""
  2234. with self.assertRaises(ValueError) as e:
  2235. self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
  2236. self.assertIn("Invalid location 'None', expected 'start' or 'end'",
  2237. str(e.exception))
  2238. def testEntryExpand(self):
  2239. """Test extending an entry after it is packed"""
  2240. data = self._DoReadFile('121_entry_extend.dts')
  2241. self.assertEqual(b'aaa', data[:3])
  2242. self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
  2243. self.assertEqual(b'aaa', data[-3:])
  2244. def testEntryExtendBad(self):
  2245. """Test extending an entry after it is packed, twice"""
  2246. with self.assertRaises(ValueError) as e:
  2247. self._DoReadFile('122_entry_extend_twice.dts')
  2248. self.assertIn("Image '/binman': Entries changed size after packing",
  2249. str(e.exception))
  2250. def testEntryExtendSection(self):
  2251. """Test extending an entry within a section after it is packed"""
  2252. data = self._DoReadFile('123_entry_extend_section.dts')
  2253. self.assertEqual(b'aaa', data[:3])
  2254. self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
  2255. self.assertEqual(b'aaa', data[-3:])
  2256. def testCompressDtb(self):
  2257. """Test that compress of device-tree files is supported"""
  2258. self._CheckLz4()
  2259. data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
  2260. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  2261. comp_data = data[len(U_BOOT_DATA):]
  2262. orig = self._decompress(comp_data)
  2263. dtb = fdt.Fdt.FromData(orig)
  2264. dtb.Scan()
  2265. props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
  2266. expected = {
  2267. 'u-boot:size': len(U_BOOT_DATA),
  2268. 'u-boot-dtb:uncomp-size': len(orig),
  2269. 'u-boot-dtb:size': len(comp_data),
  2270. 'size': len(data),
  2271. }
  2272. self.assertEqual(expected, props)
  2273. def testCbfsUpdateFdt(self):
  2274. """Test that we can update the device tree with CBFS offset/size info"""
  2275. self._CheckLz4()
  2276. data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
  2277. update_dtb=True)
  2278. dtb = fdt.Fdt(out_dtb_fname)
  2279. dtb.Scan()
  2280. props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
  2281. del props['cbfs/u-boot:size']
  2282. self.assertEqual({
  2283. 'offset': 0,
  2284. 'size': len(data),
  2285. 'image-pos': 0,
  2286. 'cbfs:offset': 0,
  2287. 'cbfs:size': len(data),
  2288. 'cbfs:image-pos': 0,
  2289. 'cbfs/u-boot:offset': 0x38,
  2290. 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
  2291. 'cbfs/u-boot:image-pos': 0x38,
  2292. 'cbfs/u-boot-dtb:offset': 0xb8,
  2293. 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
  2294. 'cbfs/u-boot-dtb:image-pos': 0xb8,
  2295. }, props)
  2296. def testCbfsBadType(self):
  2297. """Test an image header with a no specified location is detected"""
  2298. with self.assertRaises(ValueError) as e:
  2299. self._DoReadFile('126_cbfs_bad_type.dts')
  2300. self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
  2301. def testList(self):
  2302. """Test listing the files in an image"""
  2303. self._CheckLz4()
  2304. data = self._DoReadFile('127_list.dts')
  2305. image = control.images['image']
  2306. entries = image.BuildEntryList()
  2307. self.assertEqual(7, len(entries))
  2308. ent = entries[0]
  2309. self.assertEqual(0, ent.indent)
  2310. self.assertEqual('image', ent.name)
  2311. self.assertEqual('section', ent.etype)
  2312. self.assertEqual(len(data), ent.size)
  2313. self.assertEqual(0, ent.image_pos)
  2314. self.assertEqual(None, ent.uncomp_size)
  2315. self.assertEqual(0, ent.offset)
  2316. ent = entries[1]
  2317. self.assertEqual(1, ent.indent)
  2318. self.assertEqual('u-boot', ent.name)
  2319. self.assertEqual('u-boot', ent.etype)
  2320. self.assertEqual(len(U_BOOT_DATA), ent.size)
  2321. self.assertEqual(0, ent.image_pos)
  2322. self.assertEqual(None, ent.uncomp_size)
  2323. self.assertEqual(0, ent.offset)
  2324. ent = entries[2]
  2325. self.assertEqual(1, ent.indent)
  2326. self.assertEqual('section', ent.name)
  2327. self.assertEqual('section', ent.etype)
  2328. section_size = ent.size
  2329. self.assertEqual(0x100, ent.image_pos)
  2330. self.assertEqual(None, ent.uncomp_size)
  2331. self.assertEqual(0x100, ent.offset)
  2332. ent = entries[3]
  2333. self.assertEqual(2, ent.indent)
  2334. self.assertEqual('cbfs', ent.name)
  2335. self.assertEqual('cbfs', ent.etype)
  2336. self.assertEqual(0x400, ent.size)
  2337. self.assertEqual(0x100, ent.image_pos)
  2338. self.assertEqual(None, ent.uncomp_size)
  2339. self.assertEqual(0, ent.offset)
  2340. ent = entries[4]
  2341. self.assertEqual(3, ent.indent)
  2342. self.assertEqual('u-boot', ent.name)
  2343. self.assertEqual('u-boot', ent.etype)
  2344. self.assertEqual(len(U_BOOT_DATA), ent.size)
  2345. self.assertEqual(0x138, ent.image_pos)
  2346. self.assertEqual(None, ent.uncomp_size)
  2347. self.assertEqual(0x38, ent.offset)
  2348. ent = entries[5]
  2349. self.assertEqual(3, ent.indent)
  2350. self.assertEqual('u-boot-dtb', ent.name)
  2351. self.assertEqual('text', ent.etype)
  2352. self.assertGreater(len(COMPRESS_DATA), ent.size)
  2353. self.assertEqual(0x178, ent.image_pos)
  2354. self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
  2355. self.assertEqual(0x78, ent.offset)
  2356. ent = entries[6]
  2357. self.assertEqual(2, ent.indent)
  2358. self.assertEqual('u-boot-dtb', ent.name)
  2359. self.assertEqual('u-boot-dtb', ent.etype)
  2360. self.assertEqual(0x500, ent.image_pos)
  2361. self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
  2362. dtb_size = ent.size
  2363. # Compressing this data expands it since headers are added
  2364. self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
  2365. self.assertEqual(0x400, ent.offset)
  2366. self.assertEqual(len(data), 0x100 + section_size)
  2367. self.assertEqual(section_size, 0x400 + dtb_size)
  2368. def testFindFdtmap(self):
  2369. """Test locating an FDT map in an image"""
  2370. self._CheckLz4()
  2371. data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
  2372. image = control.images['image']
  2373. entries = image.GetEntries()
  2374. entry = entries['fdtmap']
  2375. self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
  2376. def testFindFdtmapMissing(self):
  2377. """Test failing to locate an FDP map"""
  2378. data = self._DoReadFile('005_simple.dts')
  2379. self.assertEqual(None, fdtmap.LocateFdtmap(data))
  2380. def testFindImageHeader(self):
  2381. """Test locating a image header"""
  2382. self._CheckLz4()
  2383. data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
  2384. image = control.images['image']
  2385. entries = image.GetEntries()
  2386. entry = entries['fdtmap']
  2387. # The header should point to the FDT map
  2388. self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
  2389. def testFindImageHeaderStart(self):
  2390. """Test locating a image header located at the start of an image"""
  2391. data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
  2392. image = control.images['image']
  2393. entries = image.GetEntries()
  2394. entry = entries['fdtmap']
  2395. # The header should point to the FDT map
  2396. self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
  2397. def testFindImageHeaderMissing(self):
  2398. """Test failing to locate an image header"""
  2399. data = self._DoReadFile('005_simple.dts')
  2400. self.assertEqual(None, image_header.LocateHeaderOffset(data))
  2401. def testReadImage(self):
  2402. """Test reading an image and accessing its FDT map"""
  2403. self._CheckLz4()
  2404. data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
  2405. image_fname = tools.get_output_filename('image.bin')
  2406. orig_image = control.images['image']
  2407. image = Image.FromFile(image_fname)
  2408. self.assertEqual(orig_image.GetEntries().keys(),
  2409. image.GetEntries().keys())
  2410. orig_entry = orig_image.GetEntries()['fdtmap']
  2411. entry = image.GetEntries()['fdtmap']
  2412. self.assertEquals(orig_entry.offset, entry.offset)
  2413. self.assertEquals(orig_entry.size, entry.size)
  2414. self.assertEquals(orig_entry.image_pos, entry.image_pos)
  2415. def testReadImageNoHeader(self):
  2416. """Test accessing an image's FDT map without an image header"""
  2417. self._CheckLz4()
  2418. data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
  2419. image_fname = tools.get_output_filename('image.bin')
  2420. image = Image.FromFile(image_fname)
  2421. self.assertTrue(isinstance(image, Image))
  2422. self.assertEqual('image', image.image_name[-5:])
  2423. def testReadImageFail(self):
  2424. """Test failing to read an image image's FDT map"""
  2425. self._DoReadFile('005_simple.dts')
  2426. image_fname = tools.get_output_filename('image.bin')
  2427. with self.assertRaises(ValueError) as e:
  2428. image = Image.FromFile(image_fname)
  2429. self.assertIn("Cannot find FDT map in image", str(e.exception))
  2430. def testListCmd(self):
  2431. """Test listing the files in an image using an Fdtmap"""
  2432. self._CheckLz4()
  2433. data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2434. # lz4 compression size differs depending on the version
  2435. image = control.images['image']
  2436. entries = image.GetEntries()
  2437. section_size = entries['section'].size
  2438. fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
  2439. fdtmap_offset = entries['fdtmap'].offset
  2440. try:
  2441. tmpdir, updated_fname = self._SetupImageInTmpdir()
  2442. with test_util.capture_sys_output() as (stdout, stderr):
  2443. self._DoBinman('ls', '-i', updated_fname)
  2444. finally:
  2445. shutil.rmtree(tmpdir)
  2446. lines = stdout.getvalue().splitlines()
  2447. expected = [
  2448. 'Name Image-pos Size Entry-type Offset Uncomp-size',
  2449. '----------------------------------------------------------------------',
  2450. 'image 0 c00 section 0',
  2451. ' u-boot 0 4 u-boot 0',
  2452. ' section 100 %x section 100' % section_size,
  2453. ' cbfs 100 400 cbfs 0',
  2454. ' u-boot 138 4 u-boot 38',
  2455. ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
  2456. ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
  2457. ' fdtmap %x 3bd fdtmap %x' %
  2458. (fdtmap_offset, fdtmap_offset),
  2459. ' image-header bf8 8 image-header bf8',
  2460. ]
  2461. self.assertEqual(expected, lines)
  2462. def testListCmdFail(self):
  2463. """Test failing to list an image"""
  2464. self._DoReadFile('005_simple.dts')
  2465. try:
  2466. tmpdir, updated_fname = self._SetupImageInTmpdir()
  2467. with self.assertRaises(ValueError) as e:
  2468. self._DoBinman('ls', '-i', updated_fname)
  2469. finally:
  2470. shutil.rmtree(tmpdir)
  2471. self.assertIn("Cannot find FDT map in image", str(e.exception))
  2472. def _RunListCmd(self, paths, expected):
  2473. """List out entries and check the result
  2474. Args:
  2475. paths: List of paths to pass to the list command
  2476. expected: Expected list of filenames to be returned, in order
  2477. """
  2478. self._CheckLz4()
  2479. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2480. image_fname = tools.get_output_filename('image.bin')
  2481. image = Image.FromFile(image_fname)
  2482. lines = image.GetListEntries(paths)[1]
  2483. files = [line[0].strip() for line in lines[1:]]
  2484. self.assertEqual(expected, files)
  2485. def testListCmdSection(self):
  2486. """Test listing the files in a section"""
  2487. self._RunListCmd(['section'],
  2488. ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
  2489. def testListCmdFile(self):
  2490. """Test listing a particular file"""
  2491. self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
  2492. def testListCmdWildcard(self):
  2493. """Test listing a wildcarded file"""
  2494. self._RunListCmd(['*boot*'],
  2495. ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
  2496. def testListCmdWildcardMulti(self):
  2497. """Test listing a wildcarded file"""
  2498. self._RunListCmd(['*cb*', '*head*'],
  2499. ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
  2500. def testListCmdEmpty(self):
  2501. """Test listing a wildcarded file"""
  2502. self._RunListCmd(['nothing'], [])
  2503. def testListCmdPath(self):
  2504. """Test listing the files in a sub-entry of a section"""
  2505. self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
  2506. def _RunExtractCmd(self, entry_name, decomp=True):
  2507. """Extract an entry from an image
  2508. Args:
  2509. entry_name: Entry name to extract
  2510. decomp: True to decompress the data if compressed, False to leave
  2511. it in its raw uncompressed format
  2512. Returns:
  2513. data from entry
  2514. """
  2515. self._CheckLz4()
  2516. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2517. image_fname = tools.get_output_filename('image.bin')
  2518. return control.ReadEntry(image_fname, entry_name, decomp)
  2519. def testExtractSimple(self):
  2520. """Test extracting a single file"""
  2521. data = self._RunExtractCmd('u-boot')
  2522. self.assertEqual(U_BOOT_DATA, data)
  2523. def testExtractSection(self):
  2524. """Test extracting the files in a section"""
  2525. data = self._RunExtractCmd('section')
  2526. cbfs_data = data[:0x400]
  2527. cbfs = cbfs_util.CbfsReader(cbfs_data)
  2528. self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
  2529. dtb_data = data[0x400:]
  2530. dtb = self._decompress(dtb_data)
  2531. self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
  2532. def testExtractCompressed(self):
  2533. """Test extracting compressed data"""
  2534. data = self._RunExtractCmd('section/u-boot-dtb')
  2535. self.assertEqual(EXTRACT_DTB_SIZE, len(data))
  2536. def testExtractRaw(self):
  2537. """Test extracting compressed data without decompressing it"""
  2538. data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
  2539. dtb = self._decompress(data)
  2540. self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
  2541. def testExtractCbfs(self):
  2542. """Test extracting CBFS data"""
  2543. data = self._RunExtractCmd('section/cbfs/u-boot')
  2544. self.assertEqual(U_BOOT_DATA, data)
  2545. def testExtractCbfsCompressed(self):
  2546. """Test extracting CBFS compressed data"""
  2547. data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
  2548. self.assertEqual(EXTRACT_DTB_SIZE, len(data))
  2549. def testExtractCbfsRaw(self):
  2550. """Test extracting CBFS compressed data without decompressing it"""
  2551. bintool = self.comp_bintools['lzma_alone']
  2552. self._CheckBintool(bintool)
  2553. data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
  2554. dtb = bintool.decompress(data)
  2555. self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
  2556. def testExtractBadEntry(self):
  2557. """Test extracting a bad section path"""
  2558. with self.assertRaises(ValueError) as e:
  2559. self._RunExtractCmd('section/does-not-exist')
  2560. self.assertIn("Entry 'does-not-exist' not found in '/section'",
  2561. str(e.exception))
  2562. def testExtractMissingFile(self):
  2563. """Test extracting file that does not exist"""
  2564. with self.assertRaises(IOError) as e:
  2565. control.ReadEntry('missing-file', 'name')
  2566. def testExtractBadFile(self):
  2567. """Test extracting an invalid file"""
  2568. fname = os.path.join(self._indir, 'badfile')
  2569. tools.write_file(fname, b'')
  2570. with self.assertRaises(ValueError) as e:
  2571. control.ReadEntry(fname, 'name')
  2572. def testExtractCmd(self):
  2573. """Test extracting a file fron an image on the command line"""
  2574. self._CheckLz4()
  2575. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2576. fname = os.path.join(self._indir, 'output.extact')
  2577. try:
  2578. tmpdir, updated_fname = self._SetupImageInTmpdir()
  2579. with test_util.capture_sys_output() as (stdout, stderr):
  2580. self._DoBinman('extract', '-i', updated_fname, 'u-boot',
  2581. '-f', fname)
  2582. finally:
  2583. shutil.rmtree(tmpdir)
  2584. data = tools.read_file(fname)
  2585. self.assertEqual(U_BOOT_DATA, data)
  2586. def testExtractOneEntry(self):
  2587. """Test extracting a single entry fron an image """
  2588. self._CheckLz4()
  2589. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2590. image_fname = tools.get_output_filename('image.bin')
  2591. fname = os.path.join(self._indir, 'output.extact')
  2592. control.ExtractEntries(image_fname, fname, None, ['u-boot'])
  2593. data = tools.read_file(fname)
  2594. self.assertEqual(U_BOOT_DATA, data)
  2595. def _CheckExtractOutput(self, decomp):
  2596. """Helper to test file output with and without decompression
  2597. Args:
  2598. decomp: True to decompress entry data, False to output it raw
  2599. """
  2600. def _CheckPresent(entry_path, expect_data, expect_size=None):
  2601. """Check and remove expected file
  2602. This checks the data/size of a file and removes the file both from
  2603. the outfiles set and from the output directory. Once all files are
  2604. processed, both the set and directory should be empty.
  2605. Args:
  2606. entry_path: Entry path
  2607. expect_data: Data to expect in file, or None to skip check
  2608. expect_size: Size of data to expect in file, or None to skip
  2609. """
  2610. path = os.path.join(outdir, entry_path)
  2611. data = tools.read_file(path)
  2612. os.remove(path)
  2613. if expect_data:
  2614. self.assertEqual(expect_data, data)
  2615. elif expect_size:
  2616. self.assertEqual(expect_size, len(data))
  2617. outfiles.remove(path)
  2618. def _CheckDirPresent(name):
  2619. """Remove expected directory
  2620. This gives an error if the directory does not exist as expected
  2621. Args:
  2622. name: Name of directory to remove
  2623. """
  2624. path = os.path.join(outdir, name)
  2625. os.rmdir(path)
  2626. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2627. image_fname = tools.get_output_filename('image.bin')
  2628. outdir = os.path.join(self._indir, 'extract')
  2629. einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
  2630. # Create a set of all file that were output (should be 9)
  2631. outfiles = set()
  2632. for root, dirs, files in os.walk(outdir):
  2633. outfiles |= set([os.path.join(root, fname) for fname in files])
  2634. self.assertEqual(9, len(outfiles))
  2635. self.assertEqual(9, len(einfos))
  2636. image = control.images['image']
  2637. entries = image.GetEntries()
  2638. # Check the 9 files in various ways
  2639. section = entries['section']
  2640. section_entries = section.GetEntries()
  2641. cbfs_entries = section_entries['cbfs'].GetEntries()
  2642. _CheckPresent('u-boot', U_BOOT_DATA)
  2643. _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
  2644. dtb_len = EXTRACT_DTB_SIZE
  2645. if not decomp:
  2646. dtb_len = cbfs_entries['u-boot-dtb'].size
  2647. _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
  2648. if not decomp:
  2649. dtb_len = section_entries['u-boot-dtb'].size
  2650. _CheckPresent('section/u-boot-dtb', None, dtb_len)
  2651. fdtmap = entries['fdtmap']
  2652. _CheckPresent('fdtmap', fdtmap.data)
  2653. hdr = entries['image-header']
  2654. _CheckPresent('image-header', hdr.data)
  2655. _CheckPresent('section/root', section.data)
  2656. cbfs = section_entries['cbfs']
  2657. _CheckPresent('section/cbfs/root', cbfs.data)
  2658. data = tools.read_file(image_fname)
  2659. _CheckPresent('root', data)
  2660. # There should be no files left. Remove all the directories to check.
  2661. # If there are any files/dirs remaining, one of these checks will fail.
  2662. self.assertEqual(0, len(outfiles))
  2663. _CheckDirPresent('section/cbfs')
  2664. _CheckDirPresent('section')
  2665. _CheckDirPresent('')
  2666. self.assertFalse(os.path.exists(outdir))
  2667. def testExtractAllEntries(self):
  2668. """Test extracting all entries"""
  2669. self._CheckLz4()
  2670. self._CheckExtractOutput(decomp=True)
  2671. def testExtractAllEntriesRaw(self):
  2672. """Test extracting all entries without decompressing them"""
  2673. self._CheckLz4()
  2674. self._CheckExtractOutput(decomp=False)
  2675. def testExtractSelectedEntries(self):
  2676. """Test extracting some entries"""
  2677. self._CheckLz4()
  2678. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2679. image_fname = tools.get_output_filename('image.bin')
  2680. outdir = os.path.join(self._indir, 'extract')
  2681. einfos = control.ExtractEntries(image_fname, None, outdir,
  2682. ['*cb*', '*head*'])
  2683. # File output is tested by testExtractAllEntries(), so just check that
  2684. # the expected entries are selected
  2685. names = [einfo.name for einfo in einfos]
  2686. self.assertEqual(names,
  2687. ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
  2688. def testExtractNoEntryPaths(self):
  2689. """Test extracting some entries"""
  2690. self._CheckLz4()
  2691. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2692. image_fname = tools.get_output_filename('image.bin')
  2693. with self.assertRaises(ValueError) as e:
  2694. control.ExtractEntries(image_fname, 'fname', None, [])
  2695. self.assertIn('Must specify an entry path to write with -f',
  2696. str(e.exception))
  2697. def testExtractTooManyEntryPaths(self):
  2698. """Test extracting some entries"""
  2699. self._CheckLz4()
  2700. self._DoReadFileRealDtb('130_list_fdtmap.dts')
  2701. image_fname = tools.get_output_filename('image.bin')
  2702. with self.assertRaises(ValueError) as e:
  2703. control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
  2704. self.assertIn('Must specify exactly one entry path to write with -f',
  2705. str(e.exception))
  2706. def testPackAlignSection(self):
  2707. """Test that sections can have alignment"""
  2708. self._DoReadFile('131_pack_align_section.dts')
  2709. self.assertIn('image', control.images)
  2710. image = control.images['image']
  2711. entries = image.GetEntries()
  2712. self.assertEqual(3, len(entries))
  2713. # First u-boot
  2714. self.assertIn('u-boot', entries)
  2715. entry = entries['u-boot']
  2716. self.assertEqual(0, entry.offset)
  2717. self.assertEqual(0, entry.image_pos)
  2718. self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
  2719. self.assertEqual(len(U_BOOT_DATA), entry.size)
  2720. # Section0
  2721. self.assertIn('section0', entries)
  2722. section0 = entries['section0']
  2723. self.assertEqual(0x10, section0.offset)
  2724. self.assertEqual(0x10, section0.image_pos)
  2725. self.assertEqual(len(U_BOOT_DATA), section0.size)
  2726. # Second u-boot
  2727. section_entries = section0.GetEntries()
  2728. self.assertIn('u-boot', section_entries)
  2729. entry = section_entries['u-boot']
  2730. self.assertEqual(0, entry.offset)
  2731. self.assertEqual(0x10, entry.image_pos)
  2732. self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
  2733. self.assertEqual(len(U_BOOT_DATA), entry.size)
  2734. # Section1
  2735. self.assertIn('section1', entries)
  2736. section1 = entries['section1']
  2737. self.assertEqual(0x14, section1.offset)
  2738. self.assertEqual(0x14, section1.image_pos)
  2739. self.assertEqual(0x20, section1.size)
  2740. # Second u-boot
  2741. section_entries = section1.GetEntries()
  2742. self.assertIn('u-boot', section_entries)
  2743. entry = section_entries['u-boot']
  2744. self.assertEqual(0, entry.offset)
  2745. self.assertEqual(0x14, entry.image_pos)
  2746. self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
  2747. self.assertEqual(len(U_BOOT_DATA), entry.size)
  2748. # Section2
  2749. self.assertIn('section2', section_entries)
  2750. section2 = section_entries['section2']
  2751. self.assertEqual(0x4, section2.offset)
  2752. self.assertEqual(0x18, section2.image_pos)
  2753. self.assertEqual(4, section2.size)
  2754. # Third u-boot
  2755. section_entries = section2.GetEntries()
  2756. self.assertIn('u-boot', section_entries)
  2757. entry = section_entries['u-boot']
  2758. self.assertEqual(0, entry.offset)
  2759. self.assertEqual(0x18, entry.image_pos)
  2760. self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
  2761. self.assertEqual(len(U_BOOT_DATA), entry.size)
  2762. def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
  2763. dts='132_replace.dts'):
  2764. """Replace an entry in an image
  2765. This writes the entry data to update it, then opens the updated file and
  2766. returns the value that it now finds there.
  2767. Args:
  2768. entry_name: Entry name to replace
  2769. data: Data to replace it with
  2770. decomp: True to compress the data if needed, False if data is
  2771. already compressed so should be used as is
  2772. allow_resize: True to allow entries to change size, False to raise
  2773. an exception
  2774. Returns:
  2775. Tuple:
  2776. data from entry
  2777. data from fdtmap (excluding header)
  2778. Image object that was modified
  2779. """
  2780. dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
  2781. update_dtb=True)[1]
  2782. self.assertIn('image', control.images)
  2783. image = control.images['image']
  2784. entries = image.GetEntries()
  2785. orig_dtb_data = entries['u-boot-dtb'].data
  2786. orig_fdtmap_data = entries['fdtmap'].data
  2787. image_fname = tools.get_output_filename('image.bin')
  2788. updated_fname = tools.get_output_filename('image-updated.bin')
  2789. tools.write_file(updated_fname, tools.read_file(image_fname))
  2790. image = control.WriteEntry(updated_fname, entry_name, data, decomp,
  2791. allow_resize)
  2792. data = control.ReadEntry(updated_fname, entry_name, decomp)
  2793. # The DT data should not change unless resized:
  2794. if not allow_resize:
  2795. new_dtb_data = entries['u-boot-dtb'].data
  2796. self.assertEqual(new_dtb_data, orig_dtb_data)
  2797. new_fdtmap_data = entries['fdtmap'].data
  2798. self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
  2799. return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
  2800. def testReplaceSimple(self):
  2801. """Test replacing a single file"""
  2802. expected = b'x' * len(U_BOOT_DATA)
  2803. data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
  2804. allow_resize=False)
  2805. self.assertEqual(expected, data)
  2806. # Test that the state looks right. There should be an FDT for the fdtmap
  2807. # that we jsut read back in, and it should match what we find in the
  2808. # 'control' tables. Checking for an FDT that does not exist should
  2809. # return None.
  2810. path, fdtmap = state.GetFdtContents('fdtmap')
  2811. self.assertIsNotNone(path)
  2812. self.assertEqual(expected_fdtmap, fdtmap)
  2813. dtb = state.GetFdtForEtype('fdtmap')
  2814. self.assertEqual(dtb.GetContents(), fdtmap)
  2815. missing_path, missing_fdtmap = state.GetFdtContents('missing')
  2816. self.assertIsNone(missing_path)
  2817. self.assertIsNone(missing_fdtmap)
  2818. missing_dtb = state.GetFdtForEtype('missing')
  2819. self.assertIsNone(missing_dtb)
  2820. self.assertEqual('/binman', state.fdt_path_prefix)
  2821. def testReplaceResizeFail(self):
  2822. """Test replacing a file by something larger"""
  2823. expected = U_BOOT_DATA + b'x'
  2824. with self.assertRaises(ValueError) as e:
  2825. self._RunReplaceCmd('u-boot', expected, allow_resize=False,
  2826. dts='139_replace_repack.dts')
  2827. self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
  2828. str(e.exception))
  2829. def testReplaceMulti(self):
  2830. """Test replacing entry data where multiple images are generated"""
  2831. data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
  2832. update_dtb=True)[0]
  2833. expected = b'x' * len(U_BOOT_DATA)
  2834. updated_fname = tools.get_output_filename('image-updated.bin')
  2835. tools.write_file(updated_fname, data)
  2836. entry_name = 'u-boot'
  2837. control.WriteEntry(updated_fname, entry_name, expected,
  2838. allow_resize=False)
  2839. data = control.ReadEntry(updated_fname, entry_name)
  2840. self.assertEqual(expected, data)
  2841. # Check the state looks right.
  2842. self.assertEqual('/binman/image', state.fdt_path_prefix)
  2843. # Now check we can write the first image
  2844. image_fname = tools.get_output_filename('first-image.bin')
  2845. updated_fname = tools.get_output_filename('first-updated.bin')
  2846. tools.write_file(updated_fname, tools.read_file(image_fname))
  2847. entry_name = 'u-boot'
  2848. control.WriteEntry(updated_fname, entry_name, expected,
  2849. allow_resize=False)
  2850. data = control.ReadEntry(updated_fname, entry_name)
  2851. self.assertEqual(expected, data)
  2852. # Check the state looks right.
  2853. self.assertEqual('/binman/first-image', state.fdt_path_prefix)
  2854. def testUpdateFdtAllRepack(self):
  2855. """Test that all device trees are updated with offset/size info"""
  2856. self._SetupSplElf()
  2857. self._SetupTplElf()
  2858. data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
  2859. SECTION_SIZE = 0x300
  2860. DTB_SIZE = 602
  2861. FDTMAP_SIZE = 608
  2862. base_expected = {
  2863. 'offset': 0,
  2864. 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
  2865. 'image-pos': 0,
  2866. 'section:offset': 0,
  2867. 'section:size': SECTION_SIZE,
  2868. 'section:image-pos': 0,
  2869. 'section/u-boot-dtb:offset': 4,
  2870. 'section/u-boot-dtb:size': 636,
  2871. 'section/u-boot-dtb:image-pos': 4,
  2872. 'u-boot-spl-dtb:offset': SECTION_SIZE,
  2873. 'u-boot-spl-dtb:size': DTB_SIZE,
  2874. 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
  2875. 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
  2876. 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
  2877. 'u-boot-tpl-dtb:size': DTB_SIZE,
  2878. 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
  2879. 'fdtmap:size': FDTMAP_SIZE,
  2880. 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
  2881. }
  2882. main_expected = {
  2883. 'section:orig-size': SECTION_SIZE,
  2884. 'section/u-boot-dtb:orig-offset': 4,
  2885. }
  2886. # We expect three device-tree files in the output, with the first one
  2887. # within a fixed-size section.
  2888. # Read them in sequence. We look for an 'spl' property in the SPL tree,
  2889. # and 'tpl' in the TPL tree, to make sure they are distinct from the
  2890. # main U-Boot tree. All three should have the same positions and offset
  2891. # except that the main tree should include the main_expected properties
  2892. start = 4
  2893. for item in ['', 'spl', 'tpl', None]:
  2894. if item is None:
  2895. start += 16 # Move past fdtmap header
  2896. dtb = fdt.Fdt.FromData(data[start:])
  2897. dtb.Scan()
  2898. props = self._GetPropTree(dtb,
  2899. BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
  2900. prefix='/' if item is None else '/binman/')
  2901. expected = dict(base_expected)
  2902. if item:
  2903. expected[item] = 0
  2904. else:
  2905. # Main DTB and fdtdec should include the 'orig-' properties
  2906. expected.update(main_expected)
  2907. # Helpful for debugging:
  2908. #for prop in sorted(props):
  2909. #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
  2910. self.assertEqual(expected, props)
  2911. if item == '':
  2912. start = SECTION_SIZE
  2913. else:
  2914. start += dtb._fdt_obj.totalsize()
  2915. def testFdtmapHeaderMiddle(self):
  2916. """Test an FDT map in the middle of an image when it should be at end"""
  2917. with self.assertRaises(ValueError) as e:
  2918. self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
  2919. self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
  2920. str(e.exception))
  2921. def testFdtmapHeaderStartBad(self):
  2922. """Test an FDT map in middle of an image when it should be at start"""
  2923. with self.assertRaises(ValueError) as e:
  2924. self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
  2925. self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
  2926. str(e.exception))
  2927. def testFdtmapHeaderEndBad(self):
  2928. """Test an FDT map at the start of an image when it should be at end"""
  2929. with self.assertRaises(ValueError) as e:
  2930. self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
  2931. self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
  2932. str(e.exception))
  2933. def testFdtmapHeaderNoSize(self):
  2934. """Test an image header at the end of an image with undefined size"""
  2935. self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
  2936. def testReplaceResize(self):
  2937. """Test replacing a single file in an entry with a larger file"""
  2938. expected = U_BOOT_DATA + b'x'
  2939. data, _, image = self._RunReplaceCmd('u-boot', expected,
  2940. dts='139_replace_repack.dts')
  2941. self.assertEqual(expected, data)
  2942. entries = image.GetEntries()
  2943. dtb_data = entries['u-boot-dtb'].data
  2944. dtb = fdt.Fdt.FromData(dtb_data)
  2945. dtb.Scan()
  2946. # The u-boot section should now be larger in the dtb
  2947. node = dtb.GetNode('/binman/u-boot')
  2948. self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
  2949. # Same for the fdtmap
  2950. fdata = entries['fdtmap'].data
  2951. fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
  2952. fdtb.Scan()
  2953. fnode = fdtb.GetNode('/u-boot')
  2954. self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
  2955. def testReplaceResizeNoRepack(self):
  2956. """Test replacing an entry with a larger file when not allowed"""
  2957. expected = U_BOOT_DATA + b'x'
  2958. with self.assertRaises(ValueError) as e:
  2959. self._RunReplaceCmd('u-boot', expected)
  2960. self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
  2961. str(e.exception))
  2962. def testEntryShrink(self):
  2963. """Test contracting an entry after it is packed"""
  2964. try:
  2965. state.SetAllowEntryContraction(True)
  2966. data = self._DoReadFileDtb('140_entry_shrink.dts',
  2967. update_dtb=True)[0]
  2968. finally:
  2969. state.SetAllowEntryContraction(False)
  2970. self.assertEqual(b'a', data[:1])
  2971. self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
  2972. self.assertEqual(b'a', data[-1:])
  2973. def testEntryShrinkFail(self):
  2974. """Test not being allowed to contract an entry after it is packed"""
  2975. data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
  2976. # In this case there is a spare byte at the end of the data. The size of
  2977. # the contents is only 1 byte but we still have the size before it
  2978. # shrunk.
  2979. self.assertEqual(b'a\0', data[:2])
  2980. self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
  2981. self.assertEqual(b'a\0', data[-2:])
  2982. def testDescriptorOffset(self):
  2983. """Test that the Intel descriptor is always placed at at the start"""
  2984. data = self._DoReadFileDtb('141_descriptor_offset.dts')
  2985. image = control.images['image']
  2986. entries = image.GetEntries()
  2987. desc = entries['intel-descriptor']
  2988. self.assertEqual(0xff800000, desc.offset);
  2989. self.assertEqual(0xff800000, desc.image_pos);
  2990. def testReplaceCbfs(self):
  2991. """Test replacing a single file in CBFS without changing the size"""
  2992. self._CheckLz4()
  2993. expected = b'x' * len(U_BOOT_DATA)
  2994. data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
  2995. updated_fname = tools.get_output_filename('image-updated.bin')
  2996. tools.write_file(updated_fname, data)
  2997. entry_name = 'section/cbfs/u-boot'
  2998. control.WriteEntry(updated_fname, entry_name, expected,
  2999. allow_resize=True)
  3000. data = control.ReadEntry(updated_fname, entry_name)
  3001. self.assertEqual(expected, data)
  3002. def testReplaceResizeCbfs(self):
  3003. """Test replacing a single file in CBFS with one of a different size"""
  3004. self._CheckLz4()
  3005. expected = U_BOOT_DATA + b'x'
  3006. data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
  3007. updated_fname = tools.get_output_filename('image-updated.bin')
  3008. tools.write_file(updated_fname, data)
  3009. entry_name = 'section/cbfs/u-boot'
  3010. control.WriteEntry(updated_fname, entry_name, expected,
  3011. allow_resize=True)
  3012. data = control.ReadEntry(updated_fname, entry_name)
  3013. self.assertEqual(expected, data)
  3014. def _SetupForReplace(self):
  3015. """Set up some files to use to replace entries
  3016. This generates an image, copies it to a new file, extracts all the files
  3017. in it and updates some of them
  3018. Returns:
  3019. List
  3020. Image filename
  3021. Output directory
  3022. Expected values for updated entries, each a string
  3023. """
  3024. data = self._DoReadFileRealDtb('143_replace_all.dts')
  3025. updated_fname = tools.get_output_filename('image-updated.bin')
  3026. tools.write_file(updated_fname, data)
  3027. outdir = os.path.join(self._indir, 'extract')
  3028. einfos = control.ExtractEntries(updated_fname, None, outdir, [])
  3029. expected1 = b'x' + U_BOOT_DATA + b'y'
  3030. u_boot_fname1 = os.path.join(outdir, 'u-boot')
  3031. tools.write_file(u_boot_fname1, expected1)
  3032. expected2 = b'a' + U_BOOT_DATA + b'b'
  3033. u_boot_fname2 = os.path.join(outdir, 'u-boot2')
  3034. tools.write_file(u_boot_fname2, expected2)
  3035. expected_text = b'not the same text'
  3036. text_fname = os.path.join(outdir, 'text')
  3037. tools.write_file(text_fname, expected_text)
  3038. dtb_fname = os.path.join(outdir, 'u-boot-dtb')
  3039. dtb = fdt.FdtScan(dtb_fname)
  3040. node = dtb.GetNode('/binman/text')
  3041. node.AddString('my-property', 'the value')
  3042. dtb.Sync(auto_resize=True)
  3043. dtb.Flush()
  3044. return updated_fname, outdir, expected1, expected2, expected_text
  3045. def _CheckReplaceMultiple(self, entry_paths):
  3046. """Handle replacing the contents of multiple entries
  3047. Args:
  3048. entry_paths: List of entry paths to replace
  3049. Returns:
  3050. List
  3051. Dict of entries in the image:
  3052. key: Entry name
  3053. Value: Entry object
  3054. Expected values for updated entries, each a string
  3055. """
  3056. updated_fname, outdir, expected1, expected2, expected_text = (
  3057. self._SetupForReplace())
  3058. control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
  3059. image = Image.FromFile(updated_fname)
  3060. image.LoadData()
  3061. return image.GetEntries(), expected1, expected2, expected_text
  3062. def testReplaceAll(self):
  3063. """Test replacing the contents of all entries"""
  3064. entries, expected1, expected2, expected_text = (
  3065. self._CheckReplaceMultiple([]))
  3066. data = entries['u-boot'].data
  3067. self.assertEqual(expected1, data)
  3068. data = entries['u-boot2'].data
  3069. self.assertEqual(expected2, data)
  3070. data = entries['text'].data
  3071. self.assertEqual(expected_text, data)
  3072. # Check that the device tree is updated
  3073. data = entries['u-boot-dtb'].data
  3074. dtb = fdt.Fdt.FromData(data)
  3075. dtb.Scan()
  3076. node = dtb.GetNode('/binman/text')
  3077. self.assertEqual('the value', node.props['my-property'].value)
  3078. def testReplaceSome(self):
  3079. """Test replacing the contents of a few entries"""
  3080. entries, expected1, expected2, expected_text = (
  3081. self._CheckReplaceMultiple(['u-boot2', 'text']))
  3082. # This one should not change
  3083. data = entries['u-boot'].data
  3084. self.assertEqual(U_BOOT_DATA, data)
  3085. data = entries['u-boot2'].data
  3086. self.assertEqual(expected2, data)
  3087. data = entries['text'].data
  3088. self.assertEqual(expected_text, data)
  3089. def testReplaceCmd(self):
  3090. """Test replacing a file fron an image on the command line"""
  3091. self._DoReadFileRealDtb('143_replace_all.dts')
  3092. try:
  3093. tmpdir, updated_fname = self._SetupImageInTmpdir()
  3094. fname = os.path.join(tmpdir, 'update-u-boot.bin')
  3095. expected = b'x' * len(U_BOOT_DATA)
  3096. tools.write_file(fname, expected)
  3097. self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
  3098. data = tools.read_file(updated_fname)
  3099. self.assertEqual(expected, data[:len(expected)])
  3100. map_fname = os.path.join(tmpdir, 'image-updated.map')
  3101. self.assertFalse(os.path.exists(map_fname))
  3102. finally:
  3103. shutil.rmtree(tmpdir)
  3104. def testReplaceCmdSome(self):
  3105. """Test replacing some files fron an image on the command line"""
  3106. updated_fname, outdir, expected1, expected2, expected_text = (
  3107. self._SetupForReplace())
  3108. self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
  3109. 'u-boot2', 'text')
  3110. tools.prepare_output_dir(None)
  3111. image = Image.FromFile(updated_fname)
  3112. image.LoadData()
  3113. entries = image.GetEntries()
  3114. # This one should not change
  3115. data = entries['u-boot'].data
  3116. self.assertEqual(U_BOOT_DATA, data)
  3117. data = entries['u-boot2'].data
  3118. self.assertEqual(expected2, data)
  3119. data = entries['text'].data
  3120. self.assertEqual(expected_text, data)
  3121. def testReplaceMissing(self):
  3122. """Test replacing entries where the file is missing"""
  3123. updated_fname, outdir, expected1, expected2, expected_text = (
  3124. self._SetupForReplace())
  3125. # Remove one of the files, to generate a warning
  3126. u_boot_fname1 = os.path.join(outdir, 'u-boot')
  3127. os.remove(u_boot_fname1)
  3128. with test_util.capture_sys_output() as (stdout, stderr):
  3129. control.ReplaceEntries(updated_fname, None, outdir, [])
  3130. self.assertIn("Skipping entry '/u-boot' from missing file",
  3131. stderr.getvalue())
  3132. def testReplaceCmdMap(self):
  3133. """Test replacing a file fron an image on the command line"""
  3134. self._DoReadFileRealDtb('143_replace_all.dts')
  3135. try:
  3136. tmpdir, updated_fname = self._SetupImageInTmpdir()
  3137. fname = os.path.join(self._indir, 'update-u-boot.bin')
  3138. expected = b'x' * len(U_BOOT_DATA)
  3139. tools.write_file(fname, expected)
  3140. self._DoBinman('replace', '-i', updated_fname, 'u-boot',
  3141. '-f', fname, '-m')
  3142. map_fname = os.path.join(tmpdir, 'image-updated.map')
  3143. self.assertTrue(os.path.exists(map_fname))
  3144. finally:
  3145. shutil.rmtree(tmpdir)
  3146. def testReplaceNoEntryPaths(self):
  3147. """Test replacing an entry without an entry path"""
  3148. self._DoReadFileRealDtb('143_replace_all.dts')
  3149. image_fname = tools.get_output_filename('image.bin')
  3150. with self.assertRaises(ValueError) as e:
  3151. control.ReplaceEntries(image_fname, 'fname', None, [])
  3152. self.assertIn('Must specify an entry path to read with -f',
  3153. str(e.exception))
  3154. def testReplaceTooManyEntryPaths(self):
  3155. """Test extracting some entries"""
  3156. self._DoReadFileRealDtb('143_replace_all.dts')
  3157. image_fname = tools.get_output_filename('image.bin')
  3158. with self.assertRaises(ValueError) as e:
  3159. control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
  3160. self.assertIn('Must specify exactly one entry path to write with -f',
  3161. str(e.exception))
  3162. def testPackReset16(self):
  3163. """Test that an image with an x86 reset16 region can be created"""
  3164. data = self._DoReadFile('144_x86_reset16.dts')
  3165. self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
  3166. def testPackReset16Spl(self):
  3167. """Test that an image with an x86 reset16-spl region can be created"""
  3168. data = self._DoReadFile('145_x86_reset16_spl.dts')
  3169. self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
  3170. def testPackReset16Tpl(self):
  3171. """Test that an image with an x86 reset16-tpl region can be created"""
  3172. data = self._DoReadFile('146_x86_reset16_tpl.dts')
  3173. self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
  3174. def testPackIntelFit(self):
  3175. """Test that an image with an Intel FIT and pointer can be created"""
  3176. data = self._DoReadFile('147_intel_fit.dts')
  3177. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  3178. fit = data[16:32];
  3179. self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
  3180. ptr = struct.unpack('<i', data[0x40:0x44])[0]
  3181. image = control.images['image']
  3182. entries = image.GetEntries()
  3183. expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
  3184. self.assertEqual(expected_ptr, ptr)
  3185. def testPackIntelFitMissing(self):
  3186. """Test detection of a FIT pointer with not FIT region"""
  3187. with self.assertRaises(ValueError) as e:
  3188. self._DoReadFile('148_intel_fit_missing.dts')
  3189. self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
  3190. str(e.exception))
  3191. def _CheckSymbolsTplSection(self, dts, expected_vals):
  3192. data = self._DoReadFile(dts)
  3193. sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
  3194. upto1 = 4 + len(U_BOOT_SPL_DATA)
  3195. expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
  3196. self.assertEqual(expected1, data[:upto1])
  3197. upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
  3198. expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
  3199. self.assertEqual(expected2, data[upto1:upto2])
  3200. upto3 = 0x3c + len(U_BOOT_DATA)
  3201. expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
  3202. self.assertEqual(expected3, data[upto2:upto3])
  3203. expected4 = sym_values + U_BOOT_TPL_DATA[24:]
  3204. self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
  3205. def testSymbolsTplSection(self):
  3206. """Test binman can assign symbols embedded in U-Boot TPL in a section"""
  3207. self._SetupSplElf('u_boot_binman_syms')
  3208. self._SetupTplElf('u_boot_binman_syms')
  3209. self._CheckSymbolsTplSection('149_symbols_tpl.dts',
  3210. [0x04, 0x20, 0x10 + 0x3c, 0x04])
  3211. def testSymbolsTplSectionX86(self):
  3212. """Test binman can assign symbols in a section with end-at-4gb"""
  3213. self._SetupSplElf('u_boot_binman_syms_x86')
  3214. self._SetupTplElf('u_boot_binman_syms_x86')
  3215. self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
  3216. [0xffffff04, 0xffffff20, 0xffffff3c,
  3217. 0x04])
  3218. def testPackX86RomIfwiSectiom(self):
  3219. """Test that a section can be placed in an IFWI region"""
  3220. self._SetupIfwi('fitimage.bin')
  3221. data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
  3222. self._CheckIfwi(data)
  3223. def testPackFspM(self):
  3224. """Test that an image with a FSP memory-init binary can be created"""
  3225. data = self._DoReadFile('152_intel_fsp_m.dts')
  3226. self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
  3227. def testPackFspS(self):
  3228. """Test that an image with a FSP silicon-init binary can be created"""
  3229. data = self._DoReadFile('153_intel_fsp_s.dts')
  3230. self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
  3231. def testPackFspT(self):
  3232. """Test that an image with a FSP temp-ram-init binary can be created"""
  3233. data = self._DoReadFile('154_intel_fsp_t.dts')
  3234. self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
  3235. def testMkimage(self):
  3236. """Test using mkimage to build an image"""
  3237. self._SetupSplElf()
  3238. data = self._DoReadFile('156_mkimage.dts')
  3239. # Just check that the data appears in the file somewhere
  3240. self.assertIn(U_BOOT_SPL_DATA, data)
  3241. def testMkimageMissing(self):
  3242. """Test that binman still produces an image if mkimage is missing"""
  3243. self._SetupSplElf()
  3244. with test_util.capture_sys_output() as (_, stderr):
  3245. self._DoTestFile('156_mkimage.dts',
  3246. force_missing_bintools='mkimage')
  3247. err = stderr.getvalue()
  3248. self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
  3249. def testExtblob(self):
  3250. """Test an image with an external blob"""
  3251. data = self._DoReadFile('157_blob_ext.dts')
  3252. self.assertEqual(REFCODE_DATA, data)
  3253. def testExtblobMissing(self):
  3254. """Test an image with a missing external blob"""
  3255. with self.assertRaises(ValueError) as e:
  3256. self._DoReadFile('158_blob_ext_missing.dts')
  3257. self.assertIn("Filename 'missing-file' not found in input path",
  3258. str(e.exception))
  3259. def testExtblobMissingOk(self):
  3260. """Test an image with an missing external blob that is allowed"""
  3261. with test_util.capture_sys_output() as (stdout, stderr):
  3262. ret = self._DoTestFile('158_blob_ext_missing.dts',
  3263. allow_missing=True)
  3264. self.assertEqual(103, ret)
  3265. err = stderr.getvalue()
  3266. self.assertIn('(missing-file)', err)
  3267. self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
  3268. self.assertIn('Some images are invalid', err)
  3269. def testExtblobMissingOkFlag(self):
  3270. """Test an image with an missing external blob allowed with -W"""
  3271. with test_util.capture_sys_output() as (stdout, stderr):
  3272. ret = self._DoTestFile('158_blob_ext_missing.dts',
  3273. allow_missing=True, ignore_missing=True)
  3274. self.assertEqual(0, ret)
  3275. err = stderr.getvalue()
  3276. self.assertIn('(missing-file)', err)
  3277. self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
  3278. self.assertIn('Some images are invalid', err)
  3279. def testExtblobMissingOkSect(self):
  3280. """Test an image with an missing external blob that is allowed"""
  3281. with test_util.capture_sys_output() as (stdout, stderr):
  3282. self._DoTestFile('159_blob_ext_missing_sect.dts',
  3283. allow_missing=True)
  3284. err = stderr.getvalue()
  3285. self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
  3286. def testPackX86RomMeMissingDesc(self):
  3287. """Test that an missing Intel descriptor entry is allowed"""
  3288. with test_util.capture_sys_output() as (stdout, stderr):
  3289. self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
  3290. err = stderr.getvalue()
  3291. self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
  3292. def testPackX86RomMissingIfwi(self):
  3293. """Test that an x86 ROM with Integrated Firmware Image can be created"""
  3294. self._SetupIfwi('fitimage.bin')
  3295. pathname = os.path.join(self._indir, 'fitimage.bin')
  3296. os.remove(pathname)
  3297. with test_util.capture_sys_output() as (stdout, stderr):
  3298. self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
  3299. err = stderr.getvalue()
  3300. self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
  3301. def testPackOverlapZero(self):
  3302. """Test that zero-size overlapping regions are ignored"""
  3303. self._DoTestFile('160_pack_overlap_zero.dts')
  3304. def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
  3305. # The data should be inside the FIT
  3306. dtb = fdt.Fdt.FromData(fit_data)
  3307. dtb.Scan()
  3308. fnode = dtb.GetNode('/images/kernel')
  3309. self.assertIn('data', fnode.props)
  3310. fname = os.path.join(self._indir, 'fit_data.fit')
  3311. tools.write_file(fname, fit_data)
  3312. out = tools.run('dumpimage', '-l', fname)
  3313. # Check a few features to make sure the plumbing works. We don't need
  3314. # to test the operation of mkimage or dumpimage here. First convert the
  3315. # output into a dict where the keys are the fields printed by dumpimage
  3316. # and the values are a list of values for each field
  3317. lines = out.splitlines()
  3318. # Converts "Compression: gzip compressed" into two groups:
  3319. # 'Compression' and 'gzip compressed'
  3320. re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
  3321. vals = collections.defaultdict(list)
  3322. for line in lines:
  3323. mat = re_line.match(line)
  3324. vals[mat.group(1)].append(mat.group(2))
  3325. self.assertEquals('FIT description: test-desc', lines[0])
  3326. self.assertIn('Created:', lines[1])
  3327. self.assertIn('Image 0 (kernel)', vals)
  3328. self.assertIn('Hash value', vals)
  3329. data_sizes = vals.get('Data Size')
  3330. self.assertIsNotNone(data_sizes)
  3331. self.assertEqual(2, len(data_sizes))
  3332. # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
  3333. self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
  3334. self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
  3335. # Check if entry listing correctly omits /images/
  3336. image = control.images['image']
  3337. fit_entry = image.GetEntries()['fit']
  3338. subentries = list(fit_entry.GetEntries().keys())
  3339. expected = ['kernel', 'fdt-1']
  3340. self.assertEqual(expected, subentries)
  3341. def testSimpleFit(self):
  3342. """Test an image with a FIT inside"""
  3343. self._SetupSplElf()
  3344. data = self._DoReadFile('161_fit.dts')
  3345. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  3346. self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
  3347. fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
  3348. self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
  3349. def testSimpleFitExpandsSubentries(self):
  3350. """Test that FIT images expand their subentries"""
  3351. data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
  3352. self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
  3353. self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
  3354. fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
  3355. self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
  3356. def testSimpleFitImagePos(self):
  3357. """Test that we have correct image-pos for FIT subentries"""
  3358. data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
  3359. update_dtb=True)
  3360. dtb = fdt.Fdt(out_dtb_fname)
  3361. dtb.Scan()
  3362. props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
  3363. self.maxDiff = None
  3364. self.assertEqual({
  3365. 'image-pos': 0,
  3366. 'offset': 0,
  3367. 'size': 1890,
  3368. 'u-boot:image-pos': 0,
  3369. 'u-boot:offset': 0,
  3370. 'u-boot:size': 4,
  3371. 'fit:image-pos': 4,
  3372. 'fit:offset': 4,
  3373. 'fit:size': 1840,
  3374. 'fit/images/kernel:image-pos': 304,
  3375. 'fit/images/kernel:offset': 300,
  3376. 'fit/images/kernel:size': 4,
  3377. 'fit/images/kernel/u-boot:image-pos': 304,
  3378. 'fit/images/kernel/u-boot:offset': 0,
  3379. 'fit/images/kernel/u-boot:size': 4,
  3380. 'fit/images/fdt-1:image-pos': 552,
  3381. 'fit/images/fdt-1:offset': 548,
  3382. 'fit/images/fdt-1:size': 6,
  3383. 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
  3384. 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
  3385. 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
  3386. 'u-boot-nodtb:image-pos': 1844,
  3387. 'u-boot-nodtb:offset': 1844,
  3388. 'u-boot-nodtb:size': 46,
  3389. }, props)
  3390. # Actually check the data is where we think it is
  3391. for node, expected in [
  3392. ("u-boot", U_BOOT_DATA),
  3393. ("fit/images/kernel", U_BOOT_DATA),
  3394. ("fit/images/kernel/u-boot", U_BOOT_DATA),
  3395. ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
  3396. ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
  3397. ("u-boot-nodtb", U_BOOT_NODTB_DATA),
  3398. ]:
  3399. image_pos = props[f"{node}:image-pos"]
  3400. size = props[f"{node}:size"]
  3401. self.assertEqual(len(expected), size)
  3402. self.assertEqual(expected, data[image_pos:image_pos+size])
  3403. def testFitExternal(self):
  3404. """Test an image with an FIT with external images"""
  3405. data = self._DoReadFile('162_fit_external.dts')
  3406. fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
  3407. # Size of the external-data region as set up by mkimage
  3408. external_data_size = len(U_BOOT_DATA) + 2
  3409. expected_size = (len(U_BOOT_DATA) + 0x400 +
  3410. tools.align(external_data_size, 4) +
  3411. len(U_BOOT_NODTB_DATA))
  3412. # The data should be outside the FIT
  3413. dtb = fdt.Fdt.FromData(fit_data)
  3414. dtb.Scan()
  3415. fnode = dtb.GetNode('/images/kernel')
  3416. self.assertNotIn('data', fnode.props)
  3417. self.assertEqual(len(U_BOOT_DATA),
  3418. fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
  3419. fit_pos = 0x400;
  3420. self.assertEqual(
  3421. fit_pos,
  3422. fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
  3423. self.assertEquals(expected_size, len(data))
  3424. actual_pos = len(U_BOOT_DATA) + fit_pos
  3425. self.assertEqual(U_BOOT_DATA + b'aa',
  3426. data[actual_pos:actual_pos + external_data_size])
  3427. def testFitExternalImagePos(self):
  3428. """Test that we have correct image-pos for external FIT subentries"""
  3429. data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
  3430. update_dtb=True)
  3431. dtb = fdt.Fdt(out_dtb_fname)
  3432. dtb.Scan()
  3433. props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
  3434. self.assertEqual({
  3435. 'image-pos': 0,
  3436. 'offset': 0,
  3437. 'size': 1082,
  3438. 'u-boot:image-pos': 0,
  3439. 'u-boot:offset': 0,
  3440. 'u-boot:size': 4,
  3441. 'fit:size': 1032,
  3442. 'fit:offset': 4,
  3443. 'fit:image-pos': 4,
  3444. 'fit/images/kernel:size': 4,
  3445. 'fit/images/kernel:offset': 1024,
  3446. 'fit/images/kernel:image-pos': 1028,
  3447. 'fit/images/kernel/u-boot:size': 4,
  3448. 'fit/images/kernel/u-boot:offset': 0,
  3449. 'fit/images/kernel/u-boot:image-pos': 1028,
  3450. 'fit/images/fdt-1:size': 2,
  3451. 'fit/images/fdt-1:offset': 1028,
  3452. 'fit/images/fdt-1:image-pos': 1032,
  3453. 'fit/images/fdt-1/_testing:size': 2,
  3454. 'fit/images/fdt-1/_testing:offset': 0,
  3455. 'fit/images/fdt-1/_testing:image-pos': 1032,
  3456. 'u-boot-nodtb:image-pos': 1036,
  3457. 'u-boot-nodtb:offset': 1036,
  3458. 'u-boot-nodtb:size': 46,
  3459. }, props)
  3460. # Actually check the data is where we think it is
  3461. for node, expected in [
  3462. ("u-boot", U_BOOT_DATA),
  3463. ("fit/images/kernel", U_BOOT_DATA),
  3464. ("fit/images/kernel/u-boot", U_BOOT_DATA),
  3465. ("fit/images/fdt-1", b'aa'),
  3466. ("fit/images/fdt-1/_testing", b'aa'),
  3467. ("u-boot-nodtb", U_BOOT_NODTB_DATA),
  3468. ]:
  3469. image_pos = props[f"{node}:image-pos"]
  3470. size = props[f"{node}:size"]
  3471. self.assertEqual(len(expected), size)
  3472. self.assertEqual(expected, data[image_pos:image_pos+size])
  3473. def testFitMissing(self):
  3474. """Test that binman complains if mkimage is missing"""
  3475. with self.assertRaises(ValueError) as e:
  3476. self._DoTestFile('162_fit_external.dts',
  3477. force_missing_bintools='mkimage')
  3478. self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
  3479. str(e.exception))
  3480. def testFitMissingOK(self):
  3481. """Test that binman still produces a FIT image if mkimage is missing"""
  3482. with test_util.capture_sys_output() as (_, stderr):
  3483. self._DoTestFile('162_fit_external.dts', allow_missing=True,
  3484. force_missing_bintools='mkimage')
  3485. err = stderr.getvalue()
  3486. self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
  3487. def testSectionIgnoreHashSignature(self):
  3488. """Test that sections ignore hash, signature nodes for its data"""
  3489. data = self._DoReadFile('165_section_ignore_hash_signature.dts')
  3490. expected = (U_BOOT_DATA + U_BOOT_DATA)
  3491. self.assertEqual(expected, data)
  3492. def testPadInSections(self):
  3493. """Test pad-before, pad-after for entries in sections"""
  3494. data, _, _, out_dtb_fname = self._DoReadFileDtb(
  3495. '166_pad_in_sections.dts', update_dtb=True)
  3496. expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
  3497. U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
  3498. U_BOOT_DATA)
  3499. self.assertEqual(expected, data)
  3500. dtb = fdt.Fdt(out_dtb_fname)
  3501. dtb.Scan()
  3502. props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
  3503. expected = {
  3504. 'image-pos': 0,
  3505. 'offset': 0,
  3506. 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
  3507. 'section:image-pos': 0,
  3508. 'section:offset': 0,
  3509. 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
  3510. 'section/before:image-pos': 0,
  3511. 'section/before:offset': 0,
  3512. 'section/before:size': len(U_BOOT_DATA),
  3513. 'section/u-boot:image-pos': 4,
  3514. 'section/u-boot:offset': 4,
  3515. 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
  3516. 'section/after:image-pos': 26,
  3517. 'section/after:offset': 26,
  3518. 'section/after:size': len(U_BOOT_DATA),
  3519. }
  3520. self.assertEqual(expected, props)
  3521. def testFitImageSubentryAlignment(self):
  3522. """Test relative alignability of FIT image subentries"""
  3523. self._SetupSplElf()
  3524. entry_args = {
  3525. 'test-id': TEXT_DATA,
  3526. }
  3527. data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
  3528. entry_args=entry_args)
  3529. dtb = fdt.Fdt.FromData(data)
  3530. dtb.Scan()
  3531. node = dtb.GetNode('/images/kernel')
  3532. data = dtb.GetProps(node)["data"].bytes
  3533. align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
  3534. expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
  3535. tools.get_bytes(0, align_pad) + U_BOOT_DATA)
  3536. self.assertEqual(expected, data)
  3537. node = dtb.GetNode('/images/fdt-1')
  3538. data = dtb.GetProps(node)["data"].bytes
  3539. expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
  3540. tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
  3541. U_BOOT_DTB_DATA)
  3542. self.assertEqual(expected, data)
  3543. def testFitExtblobMissingOk(self):
  3544. """Test a FIT with a missing external blob that is allowed"""
  3545. with test_util.capture_sys_output() as (stdout, stderr):
  3546. self._DoTestFile('168_fit_missing_blob.dts',
  3547. allow_missing=True)
  3548. err = stderr.getvalue()
  3549. self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
  3550. def testBlobNamedByArgMissing(self):
  3551. """Test handling of a missing entry arg"""
  3552. with self.assertRaises(ValueError) as e:
  3553. self._DoReadFile('068_blob_named_by_arg.dts')
  3554. self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
  3555. str(e.exception))
  3556. def testPackBl31(self):
  3557. """Test that an image with an ATF BL31 binary can be created"""
  3558. data = self._DoReadFile('169_atf_bl31.dts')
  3559. self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
  3560. def testPackScp(self):
  3561. """Test that an image with an SCP binary can be created"""
  3562. data = self._DoReadFile('172_scp.dts')
  3563. self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
  3564. def testFitFdt(self):
  3565. """Test an image with an FIT with multiple FDT images"""
  3566. def _CheckFdt(seq, expected_data):
  3567. """Check the FDT nodes
  3568. Args:
  3569. seq: Sequence number to check (0 or 1)
  3570. expected_data: Expected contents of 'data' property
  3571. """
  3572. name = 'fdt-%d' % seq
  3573. fnode = dtb.GetNode('/images/%s' % name)
  3574. self.assertIsNotNone(fnode)
  3575. self.assertEqual({'description','type', 'compression', 'data'},
  3576. set(fnode.props.keys()))
  3577. self.assertEqual(expected_data, fnode.props['data'].bytes)
  3578. self.assertEqual('fdt-test-fdt%d.dtb' % seq,
  3579. fnode.props['description'].value)
  3580. self.assertEqual(fnode.subnodes[0].name, 'hash')
  3581. def _CheckConfig(seq, expected_data):
  3582. """Check the configuration nodes
  3583. Args:
  3584. seq: Sequence number to check (0 or 1)
  3585. expected_data: Expected contents of 'data' property
  3586. """
  3587. cnode = dtb.GetNode('/configurations')
  3588. self.assertIn('default', cnode.props)
  3589. self.assertEqual('config-2', cnode.props['default'].value)
  3590. name = 'config-%d' % seq
  3591. fnode = dtb.GetNode('/configurations/%s' % name)
  3592. self.assertIsNotNone(fnode)
  3593. self.assertEqual({'description','firmware', 'loadables', 'fdt'},
  3594. set(fnode.props.keys()))
  3595. self.assertEqual('conf-test-fdt%d.dtb' % seq,
  3596. fnode.props['description'].value)
  3597. self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
  3598. entry_args = {
  3599. 'of-list': 'test-fdt1 test-fdt2',
  3600. 'default-dt': 'test-fdt2',
  3601. }
  3602. data = self._DoReadFileDtb(
  3603. '170_fit_fdt.dts',
  3604. entry_args=entry_args,
  3605. extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
  3606. self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
  3607. fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
  3608. dtb = fdt.Fdt.FromData(fit_data)
  3609. dtb.Scan()
  3610. fnode = dtb.GetNode('/images/kernel')
  3611. self.assertIn('data', fnode.props)
  3612. # Check all the properties in fdt-1 and fdt-2
  3613. _CheckFdt(1, TEST_FDT1_DATA)
  3614. _CheckFdt(2, TEST_FDT2_DATA)
  3615. # Check configurations
  3616. _CheckConfig(1, TEST_FDT1_DATA)
  3617. _CheckConfig(2, TEST_FDT2_DATA)
  3618. def testFitFdtMissingList(self):
  3619. """Test handling of a missing 'of-list' entry arg"""
  3620. with self.assertRaises(ValueError) as e:
  3621. self._DoReadFile('170_fit_fdt.dts')
  3622. self.assertIn("Generator node requires 'of-list' entry argument",
  3623. str(e.exception))
  3624. def testFitFdtEmptyList(self):
  3625. """Test handling of an empty 'of-list' entry arg"""
  3626. entry_args = {
  3627. 'of-list': '',
  3628. }
  3629. data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
  3630. def testFitFdtMissingProp(self):
  3631. """Test handling of a missing 'fit,fdt-list' property"""
  3632. with self.assertRaises(ValueError) as e:
  3633. self._DoReadFile('171_fit_fdt_missing_prop.dts')
  3634. self.assertIn("Generator node requires 'fit,fdt-list' property",
  3635. str(e.exception))
  3636. def testFitFdtMissing(self):
  3637. """Test handling of a missing 'default-dt' entry arg"""
  3638. entry_args = {
  3639. 'of-list': 'test-fdt1 test-fdt2',
  3640. }
  3641. with self.assertRaises(ValueError) as e:
  3642. self._DoReadFileDtb(
  3643. '170_fit_fdt.dts',
  3644. entry_args=entry_args,
  3645. extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
  3646. self.assertIn("Generated 'default' node requires default-dt entry argument",
  3647. str(e.exception))
  3648. def testFitFdtNotInList(self):
  3649. """Test handling of a default-dt that is not in the of-list"""
  3650. entry_args = {
  3651. 'of-list': 'test-fdt1 test-fdt2',
  3652. 'default-dt': 'test-fdt3',
  3653. }
  3654. with self.assertRaises(ValueError) as e:
  3655. self._DoReadFileDtb(
  3656. '170_fit_fdt.dts',
  3657. entry_args=entry_args,
  3658. extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
  3659. self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
  3660. str(e.exception))
  3661. def testFitExtblobMissingHelp(self):
  3662. """Test display of help messages when an external blob is missing"""
  3663. control.missing_blob_help = control._ReadMissingBlobHelp()
  3664. control.missing_blob_help['wibble'] = 'Wibble test'
  3665. control.missing_blob_help['another'] = 'Another test'
  3666. with test_util.capture_sys_output() as (stdout, stderr):
  3667. self._DoTestFile('168_fit_missing_blob.dts',
  3668. allow_missing=True)
  3669. err = stderr.getvalue()
  3670. # We can get the tag from the name, the type or the missing-msg
  3671. # property. Check all three.
  3672. self.assertIn('You may need to build ARM Trusted', err)
  3673. self.assertIn('Wibble test', err)
  3674. self.assertIn('Another test', err)
  3675. def testMissingBlob(self):
  3676. """Test handling of a blob containing a missing file"""
  3677. with self.assertRaises(ValueError) as e:
  3678. self._DoTestFile('173_missing_blob.dts', allow_missing=True)
  3679. self.assertIn("Filename 'missing' not found in input path",
  3680. str(e.exception))
  3681. def testEnvironment(self):
  3682. """Test adding a U-Boot environment"""
  3683. data = self._DoReadFile('174_env.dts')
  3684. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  3685. self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
  3686. env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
  3687. self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
  3688. env)
  3689. def testEnvironmentNoSize(self):
  3690. """Test that a missing 'size' property is detected"""
  3691. with self.assertRaises(ValueError) as e:
  3692. self._DoTestFile('175_env_no_size.dts')
  3693. self.assertIn("'u-boot-env' entry must have a size property",
  3694. str(e.exception))
  3695. def testEnvironmentTooSmall(self):
  3696. """Test handling of an environment that does not fit"""
  3697. with self.assertRaises(ValueError) as e:
  3698. self._DoTestFile('176_env_too_small.dts')
  3699. # checksum, start byte, environment with \0 terminator, final \0
  3700. need = 4 + 1 + len(ENV_DATA) + 1 + 1
  3701. short = need - 0x8
  3702. self.assertIn("too small to hold data (need %#x more bytes)" % short,
  3703. str(e.exception))
  3704. def testSkipAtStart(self):
  3705. """Test handling of skip-at-start section"""
  3706. data = self._DoReadFile('177_skip_at_start.dts')
  3707. self.assertEqual(U_BOOT_DATA, data)
  3708. image = control.images['image']
  3709. entries = image.GetEntries()
  3710. section = entries['section']
  3711. self.assertEqual(0, section.offset)
  3712. self.assertEqual(len(U_BOOT_DATA), section.size)
  3713. self.assertEqual(U_BOOT_DATA, section.GetData())
  3714. entry = section.GetEntries()['u-boot']
  3715. self.assertEqual(16, entry.offset)
  3716. self.assertEqual(len(U_BOOT_DATA), entry.size)
  3717. self.assertEqual(U_BOOT_DATA, entry.data)
  3718. def testSkipAtStartPad(self):
  3719. """Test handling of skip-at-start section with padded entry"""
  3720. data = self._DoReadFile('178_skip_at_start_pad.dts')
  3721. before = tools.get_bytes(0, 8)
  3722. after = tools.get_bytes(0, 4)
  3723. all = before + U_BOOT_DATA + after
  3724. self.assertEqual(all, data)
  3725. image = control.images['image']
  3726. entries = image.GetEntries()
  3727. section = entries['section']
  3728. self.assertEqual(0, section.offset)
  3729. self.assertEqual(len(all), section.size)
  3730. self.assertEqual(all, section.GetData())
  3731. entry = section.GetEntries()['u-boot']
  3732. self.assertEqual(16, entry.offset)
  3733. self.assertEqual(len(all), entry.size)
  3734. self.assertEqual(U_BOOT_DATA, entry.data)
  3735. def testSkipAtStartSectionPad(self):
  3736. """Test handling of skip-at-start section with padding"""
  3737. data = self._DoReadFile('179_skip_at_start_section_pad.dts')
  3738. before = tools.get_bytes(0, 8)
  3739. after = tools.get_bytes(0, 4)
  3740. all = before + U_BOOT_DATA + after
  3741. self.assertEqual(all, data)
  3742. image = control.images['image']
  3743. entries = image.GetEntries()
  3744. section = entries['section']
  3745. self.assertEqual(0, section.offset)
  3746. self.assertEqual(len(all), section.size)
  3747. self.assertEqual(U_BOOT_DATA, section.data)
  3748. self.assertEqual(all, section.GetPaddedData())
  3749. entry = section.GetEntries()['u-boot']
  3750. self.assertEqual(16, entry.offset)
  3751. self.assertEqual(len(U_BOOT_DATA), entry.size)
  3752. self.assertEqual(U_BOOT_DATA, entry.data)
  3753. def testSectionPad(self):
  3754. """Testing padding with sections"""
  3755. data = self._DoReadFile('180_section_pad.dts')
  3756. expected = (tools.get_bytes(ord('&'), 3) +
  3757. tools.get_bytes(ord('!'), 5) +
  3758. U_BOOT_DATA +
  3759. tools.get_bytes(ord('!'), 1) +
  3760. tools.get_bytes(ord('&'), 2))
  3761. self.assertEqual(expected, data)
  3762. def testSectionAlign(self):
  3763. """Testing alignment with sections"""
  3764. data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
  3765. expected = (b'\0' + # fill section
  3766. tools.get_bytes(ord('&'), 1) + # padding to section align
  3767. b'\0' + # fill section
  3768. tools.get_bytes(ord('!'), 3) + # padding to u-boot align
  3769. U_BOOT_DATA +
  3770. tools.get_bytes(ord('!'), 4) + # padding to u-boot size
  3771. tools.get_bytes(ord('!'), 4)) # padding to section size
  3772. self.assertEqual(expected, data)
  3773. def testCompressImage(self):
  3774. """Test compression of the entire image"""
  3775. self._CheckLz4()
  3776. data, _, _, out_dtb_fname = self._DoReadFileDtb(
  3777. '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
  3778. dtb = fdt.Fdt(out_dtb_fname)
  3779. dtb.Scan()
  3780. props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
  3781. 'uncomp-size'])
  3782. orig = self._decompress(data)
  3783. self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
  3784. # Do a sanity check on various fields
  3785. image = control.images['image']
  3786. entries = image.GetEntries()
  3787. self.assertEqual(2, len(entries))
  3788. entry = entries['blob']
  3789. self.assertEqual(COMPRESS_DATA, entry.data)
  3790. self.assertEqual(len(COMPRESS_DATA), entry.size)
  3791. entry = entries['u-boot']
  3792. self.assertEqual(U_BOOT_DATA, entry.data)
  3793. self.assertEqual(len(U_BOOT_DATA), entry.size)
  3794. self.assertEqual(len(data), image.size)
  3795. self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
  3796. self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
  3797. orig = self._decompress(image.data)
  3798. self.assertEqual(orig, image.uncomp_data)
  3799. expected = {
  3800. 'blob:offset': 0,
  3801. 'blob:size': len(COMPRESS_DATA),
  3802. 'u-boot:offset': len(COMPRESS_DATA),
  3803. 'u-boot:size': len(U_BOOT_DATA),
  3804. 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
  3805. 'offset': 0,
  3806. 'image-pos': 0,
  3807. 'size': len(data),
  3808. }
  3809. self.assertEqual(expected, props)
  3810. def testCompressImageLess(self):
  3811. """Test compression where compression reduces the image size"""
  3812. self._CheckLz4()
  3813. data, _, _, out_dtb_fname = self._DoReadFileDtb(
  3814. '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
  3815. dtb = fdt.Fdt(out_dtb_fname)
  3816. dtb.Scan()
  3817. props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
  3818. 'uncomp-size'])
  3819. orig = self._decompress(data)
  3820. self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
  3821. # Do a sanity check on various fields
  3822. image = control.images['image']
  3823. entries = image.GetEntries()
  3824. self.assertEqual(2, len(entries))
  3825. entry = entries['blob']
  3826. self.assertEqual(COMPRESS_DATA_BIG, entry.data)
  3827. self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
  3828. entry = entries['u-boot']
  3829. self.assertEqual(U_BOOT_DATA, entry.data)
  3830. self.assertEqual(len(U_BOOT_DATA), entry.size)
  3831. self.assertEqual(len(data), image.size)
  3832. self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
  3833. self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
  3834. image.uncomp_size)
  3835. orig = self._decompress(image.data)
  3836. self.assertEqual(orig, image.uncomp_data)
  3837. expected = {
  3838. 'blob:offset': 0,
  3839. 'blob:size': len(COMPRESS_DATA_BIG),
  3840. 'u-boot:offset': len(COMPRESS_DATA_BIG),
  3841. 'u-boot:size': len(U_BOOT_DATA),
  3842. 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
  3843. 'offset': 0,
  3844. 'image-pos': 0,
  3845. 'size': len(data),
  3846. }
  3847. self.assertEqual(expected, props)
  3848. def testCompressSectionSize(self):
  3849. """Test compression of a section with a fixed size"""
  3850. self._CheckLz4()
  3851. data, _, _, out_dtb_fname = self._DoReadFileDtb(
  3852. '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
  3853. dtb = fdt.Fdt(out_dtb_fname)
  3854. dtb.Scan()
  3855. props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
  3856. 'uncomp-size'])
  3857. orig = self._decompress(data)
  3858. self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
  3859. expected = {
  3860. 'section/blob:offset': 0,
  3861. 'section/blob:size': len(COMPRESS_DATA),
  3862. 'section/u-boot:offset': len(COMPRESS_DATA),
  3863. 'section/u-boot:size': len(U_BOOT_DATA),
  3864. 'section:offset': 0,
  3865. 'section:image-pos': 0,
  3866. 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
  3867. 'section:size': 0x30,
  3868. 'offset': 0,
  3869. 'image-pos': 0,
  3870. 'size': 0x30,
  3871. }
  3872. self.assertEqual(expected, props)
  3873. def testCompressSection(self):
  3874. """Test compression of a section with no fixed size"""
  3875. self._CheckLz4()
  3876. data, _, _, out_dtb_fname = self._DoReadFileDtb(
  3877. '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
  3878. dtb = fdt.Fdt(out_dtb_fname)
  3879. dtb.Scan()
  3880. props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
  3881. 'uncomp-size'])
  3882. orig = self._decompress(data)
  3883. self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
  3884. expected = {
  3885. 'section/blob:offset': 0,
  3886. 'section/blob:size': len(COMPRESS_DATA),
  3887. 'section/u-boot:offset': len(COMPRESS_DATA),
  3888. 'section/u-boot:size': len(U_BOOT_DATA),
  3889. 'section:offset': 0,
  3890. 'section:image-pos': 0,
  3891. 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
  3892. 'section:size': len(data),
  3893. 'offset': 0,
  3894. 'image-pos': 0,
  3895. 'size': len(data),
  3896. }
  3897. self.assertEqual(expected, props)
  3898. def testLz4Missing(self):
  3899. """Test that binman still produces an image if lz4 is missing"""
  3900. with test_util.capture_sys_output() as (_, stderr):
  3901. self._DoTestFile('185_compress_section.dts',
  3902. force_missing_bintools='lz4')
  3903. err = stderr.getvalue()
  3904. self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
  3905. def testCompressExtra(self):
  3906. """Test compression of a section with no fixed size"""
  3907. self._CheckLz4()
  3908. data, _, _, out_dtb_fname = self._DoReadFileDtb(
  3909. '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
  3910. dtb = fdt.Fdt(out_dtb_fname)
  3911. dtb.Scan()
  3912. props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
  3913. 'uncomp-size'])
  3914. base = data[len(U_BOOT_DATA):]
  3915. self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
  3916. rest = base[len(U_BOOT_DATA):]
  3917. # Check compressed data
  3918. bintool = self.comp_bintools['lz4']
  3919. expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
  3920. data1 = rest[:len(expect1)]
  3921. section1 = self._decompress(data1)
  3922. self.assertEquals(expect1, data1)
  3923. self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
  3924. rest1 = rest[len(expect1):]
  3925. expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
  3926. data2 = rest1[:len(expect2)]
  3927. section2 = self._decompress(data2)
  3928. self.assertEquals(expect2, data2)
  3929. self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
  3930. rest2 = rest1[len(expect2):]
  3931. expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
  3932. len(expect2) + len(U_BOOT_DATA))
  3933. #self.assertEquals(expect_size, len(data))
  3934. #self.assertEquals(U_BOOT_DATA, rest2)
  3935. self.maxDiff = None
  3936. expected = {
  3937. 'u-boot:offset': 0,
  3938. 'u-boot:image-pos': 0,
  3939. 'u-boot:size': len(U_BOOT_DATA),
  3940. 'base:offset': len(U_BOOT_DATA),
  3941. 'base:image-pos': len(U_BOOT_DATA),
  3942. 'base:size': len(data) - len(U_BOOT_DATA),
  3943. 'base/u-boot:offset': 0,
  3944. 'base/u-boot:image-pos': len(U_BOOT_DATA),
  3945. 'base/u-boot:size': len(U_BOOT_DATA),
  3946. 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
  3947. len(expect2),
  3948. 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
  3949. len(expect2),
  3950. 'base/u-boot2:size': len(U_BOOT_DATA),
  3951. 'base/section:offset': len(U_BOOT_DATA),
  3952. 'base/section:image-pos': len(U_BOOT_DATA) * 2,
  3953. 'base/section:size': len(expect1),
  3954. 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
  3955. 'base/section/blob:offset': 0,
  3956. 'base/section/blob:size': len(COMPRESS_DATA),
  3957. 'base/section/u-boot:offset': len(COMPRESS_DATA),
  3958. 'base/section/u-boot:size': len(U_BOOT_DATA),
  3959. 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
  3960. 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
  3961. 'base/section2:size': len(expect2),
  3962. 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
  3963. 'base/section2/blob:offset': 0,
  3964. 'base/section2/blob:size': len(COMPRESS_DATA),
  3965. 'base/section2/blob2:offset': len(COMPRESS_DATA),
  3966. 'base/section2/blob2:size': len(COMPRESS_DATA),
  3967. 'offset': 0,
  3968. 'image-pos': 0,
  3969. 'size': len(data),
  3970. }
  3971. self.assertEqual(expected, props)
  3972. def testSymbolsSubsection(self):
  3973. """Test binman can assign symbols from a subsection"""
  3974. self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
  3975. def testReadImageEntryArg(self):
  3976. """Test reading an image that would need an entry arg to generate"""
  3977. entry_args = {
  3978. 'cros-ec-rw-path': 'ecrw.bin',
  3979. }
  3980. data = self.data = self._DoReadFileDtb(
  3981. '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
  3982. entry_args=entry_args)
  3983. image_fname = tools.get_output_filename('image.bin')
  3984. orig_image = control.images['image']
  3985. # This should not generate an error about the missing 'cros-ec-rw-path'
  3986. # since we are reading the image from a file. Compare with
  3987. # testEntryArgsRequired()
  3988. image = Image.FromFile(image_fname)
  3989. self.assertEqual(orig_image.GetEntries().keys(),
  3990. image.GetEntries().keys())
  3991. def testFilesAlign(self):
  3992. """Test alignment with files"""
  3993. data = self._DoReadFile('190_files_align.dts')
  3994. # The first string is 15 bytes so will align to 16
  3995. expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
  3996. self.assertEqual(expect, data)
  3997. def testReadImageSkip(self):
  3998. """Test reading an image and accessing its FDT map"""
  3999. data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
  4000. image_fname = tools.get_output_filename('image.bin')
  4001. orig_image = control.images['image']
  4002. image = Image.FromFile(image_fname)
  4003. self.assertEqual(orig_image.GetEntries().keys(),
  4004. image.GetEntries().keys())
  4005. orig_entry = orig_image.GetEntries()['fdtmap']
  4006. entry = image.GetEntries()['fdtmap']
  4007. self.assertEqual(orig_entry.offset, entry.offset)
  4008. self.assertEqual(orig_entry.size, entry.size)
  4009. self.assertEqual(16, entry.image_pos)
  4010. u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
  4011. self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
  4012. def testTplNoDtb(self):
  4013. """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
  4014. self._SetupTplElf()
  4015. data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
  4016. self.assertEqual(U_BOOT_TPL_NODTB_DATA,
  4017. data[:len(U_BOOT_TPL_NODTB_DATA)])
  4018. def testTplBssPad(self):
  4019. """Test that we can pad TPL's BSS with zeros"""
  4020. # ELF file with a '__bss_size' symbol
  4021. self._SetupTplElf()
  4022. data = self._DoReadFile('193_tpl_bss_pad.dts')
  4023. self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
  4024. data)
  4025. def testTplBssPadMissing(self):
  4026. """Test that a missing symbol is detected"""
  4027. self._SetupTplElf('u_boot_ucode_ptr')
  4028. with self.assertRaises(ValueError) as e:
  4029. self._DoReadFile('193_tpl_bss_pad.dts')
  4030. self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
  4031. str(e.exception))
  4032. def checkDtbSizes(self, data, pad_len, start):
  4033. """Check the size arguments in a dtb embedded in an image
  4034. Args:
  4035. data: The image data
  4036. pad_len: Length of the pad section in the image, in bytes
  4037. start: Start offset of the devicetree to examine, within the image
  4038. Returns:
  4039. Size of the devicetree in bytes
  4040. """
  4041. dtb_data = data[start:]
  4042. dtb = fdt.Fdt.FromData(dtb_data)
  4043. fdt_size = dtb.GetFdtObj().totalsize()
  4044. dtb.Scan()
  4045. props = self._GetPropTree(dtb, 'size')
  4046. self.assertEqual({
  4047. 'size': len(data),
  4048. 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
  4049. 'u-boot-spl/u-boot-spl-dtb:size': 801,
  4050. 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
  4051. 'u-boot-spl:size': 860,
  4052. 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
  4053. 'u-boot/u-boot-dtb:size': 781,
  4054. 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
  4055. 'u-boot:size': 827,
  4056. }, props)
  4057. return fdt_size
  4058. def testExpanded(self):
  4059. """Test that an expanded entry type is selected when needed"""
  4060. self._SetupSplElf()
  4061. self._SetupTplElf()
  4062. # SPL has a devicetree, TPL does not
  4063. entry_args = {
  4064. 'spl-dtb': '1',
  4065. 'spl-bss-pad': 'y',
  4066. 'tpl-dtb': '',
  4067. }
  4068. self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
  4069. entry_args=entry_args)
  4070. image = control.images['image']
  4071. entries = image.GetEntries()
  4072. self.assertEqual(3, len(entries))
  4073. # First, u-boot, which should be expanded into u-boot-nodtb and dtb
  4074. self.assertIn('u-boot', entries)
  4075. entry = entries['u-boot']
  4076. self.assertEqual('u-boot-expanded', entry.etype)
  4077. subent = entry.GetEntries()
  4078. self.assertEqual(2, len(subent))
  4079. self.assertIn('u-boot-nodtb', subent)
  4080. self.assertIn('u-boot-dtb', subent)
  4081. # Second, u-boot-spl, which should be expanded into three parts
  4082. self.assertIn('u-boot-spl', entries)
  4083. entry = entries['u-boot-spl']
  4084. self.assertEqual('u-boot-spl-expanded', entry.etype)
  4085. subent = entry.GetEntries()
  4086. self.assertEqual(3, len(subent))
  4087. self.assertIn('u-boot-spl-nodtb', subent)
  4088. self.assertIn('u-boot-spl-bss-pad', subent)
  4089. self.assertIn('u-boot-spl-dtb', subent)
  4090. # Third, u-boot-tpl, which should be not be expanded, since TPL has no
  4091. # devicetree
  4092. self.assertIn('u-boot-tpl', entries)
  4093. entry = entries['u-boot-tpl']
  4094. self.assertEqual('u-boot-tpl', entry.etype)
  4095. self.assertEqual(None, entry.GetEntries())
  4096. def testExpandedTpl(self):
  4097. """Test that an expanded entry type is selected for TPL when needed"""
  4098. self._SetupTplElf()
  4099. entry_args = {
  4100. 'tpl-bss-pad': 'y',
  4101. 'tpl-dtb': 'y',
  4102. }
  4103. self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
  4104. entry_args=entry_args)
  4105. image = control.images['image']
  4106. entries = image.GetEntries()
  4107. self.assertEqual(1, len(entries))
  4108. # We only have u-boot-tpl, which be expanded
  4109. self.assertIn('u-boot-tpl', entries)
  4110. entry = entries['u-boot-tpl']
  4111. self.assertEqual('u-boot-tpl-expanded', entry.etype)
  4112. subent = entry.GetEntries()
  4113. self.assertEqual(3, len(subent))
  4114. self.assertIn('u-boot-tpl-nodtb', subent)
  4115. self.assertIn('u-boot-tpl-bss-pad', subent)
  4116. self.assertIn('u-boot-tpl-dtb', subent)
  4117. def testExpandedNoPad(self):
  4118. """Test an expanded entry without BSS pad enabled"""
  4119. self._SetupSplElf()
  4120. self._SetupTplElf()
  4121. # SPL has a devicetree, TPL does not
  4122. entry_args = {
  4123. 'spl-dtb': 'something',
  4124. 'spl-bss-pad': 'n',
  4125. 'tpl-dtb': '',
  4126. }
  4127. self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
  4128. entry_args=entry_args)
  4129. image = control.images['image']
  4130. entries = image.GetEntries()
  4131. # Just check u-boot-spl, which should be expanded into two parts
  4132. self.assertIn('u-boot-spl', entries)
  4133. entry = entries['u-boot-spl']
  4134. self.assertEqual('u-boot-spl-expanded', entry.etype)
  4135. subent = entry.GetEntries()
  4136. self.assertEqual(2, len(subent))
  4137. self.assertIn('u-boot-spl-nodtb', subent)
  4138. self.assertIn('u-boot-spl-dtb', subent)
  4139. def testExpandedTplNoPad(self):
  4140. """Test that an expanded entry type with padding disabled in TPL"""
  4141. self._SetupTplElf()
  4142. entry_args = {
  4143. 'tpl-bss-pad': '',
  4144. 'tpl-dtb': 'y',
  4145. }
  4146. self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
  4147. entry_args=entry_args)
  4148. image = control.images['image']
  4149. entries = image.GetEntries()
  4150. self.assertEqual(1, len(entries))
  4151. # We only have u-boot-tpl, which be expanded
  4152. self.assertIn('u-boot-tpl', entries)
  4153. entry = entries['u-boot-tpl']
  4154. self.assertEqual('u-boot-tpl-expanded', entry.etype)
  4155. subent = entry.GetEntries()
  4156. self.assertEqual(2, len(subent))
  4157. self.assertIn('u-boot-tpl-nodtb', subent)
  4158. self.assertIn('u-boot-tpl-dtb', subent)
  4159. def testFdtInclude(self):
  4160. """Test that an Fdt is update within all binaries"""
  4161. self._SetupSplElf()
  4162. self._SetupTplElf()
  4163. # SPL has a devicetree, TPL does not
  4164. self.maxDiff = None
  4165. entry_args = {
  4166. 'spl-dtb': '1',
  4167. 'spl-bss-pad': 'y',
  4168. 'tpl-dtb': '',
  4169. }
  4170. # Build the image. It includes two separate devicetree binaries, each
  4171. # with their own contents, but all contain the binman definition.
  4172. data = self._DoReadFileDtb(
  4173. '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
  4174. update_dtb=True, entry_args=entry_args)[0]
  4175. pad_len = 10
  4176. # Check the U-Boot dtb
  4177. start = len(U_BOOT_NODTB_DATA)
  4178. fdt_size = self.checkDtbSizes(data, pad_len, start)
  4179. # Now check SPL
  4180. start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
  4181. fdt_size = self.checkDtbSizes(data, pad_len, start)
  4182. # TPL has no devicetree
  4183. start += fdt_size + len(U_BOOT_TPL_DATA)
  4184. self.assertEqual(len(data), start)
  4185. def testSymbolsExpanded(self):
  4186. """Test binman can assign symbols in expanded entries"""
  4187. entry_args = {
  4188. 'spl-dtb': '1',
  4189. }
  4190. self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
  4191. U_BOOT_SPL_DTB_DATA, 0x38,
  4192. entry_args=entry_args, use_expanded=True)
  4193. def testCollection(self):
  4194. """Test a collection"""
  4195. data = self._DoReadFile('198_collection.dts')
  4196. self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
  4197. tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
  4198. tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
  4199. data)
  4200. def testCollectionSection(self):
  4201. """Test a collection where a section must be built first"""
  4202. # Sections never have their contents when GetData() is called, but when
  4203. # BuildSectionData() is called with required=True, a section will force
  4204. # building the contents, producing an error is anything is still
  4205. # missing.
  4206. data = self._DoReadFile('199_collection_section.dts')
  4207. section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
  4208. self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
  4209. section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
  4210. data)
  4211. def testAlignDefault(self):
  4212. """Test that default alignment works on sections"""
  4213. data = self._DoReadFile('200_align_default.dts')
  4214. expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
  4215. U_BOOT_DATA)
  4216. # Special alignment for section
  4217. expected += tools.get_bytes(0, 32 - len(expected))
  4218. # No alignment within the nested section
  4219. expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
  4220. # Now the final piece, which should be default-aligned
  4221. expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
  4222. self.assertEqual(expected, data)
  4223. def testPackOpenSBI(self):
  4224. """Test that an image with an OpenSBI binary can be created"""
  4225. data = self._DoReadFile('201_opensbi.dts')
  4226. self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
  4227. def testSectionsSingleThread(self):
  4228. """Test sections without multithreading"""
  4229. data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
  4230. expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
  4231. U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
  4232. U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
  4233. self.assertEqual(expected, data)
  4234. def testThreadTimeout(self):
  4235. """Test handling a thread that takes too long"""
  4236. with self.assertRaises(ValueError) as e:
  4237. self._DoTestFile('202_section_timeout.dts',
  4238. test_section_timeout=True)
  4239. self.assertIn("Timed out obtaining contents", str(e.exception))
  4240. def testTiming(self):
  4241. """Test output of timing information"""
  4242. data = self._DoReadFile('055_sections.dts')
  4243. with test_util.capture_sys_output() as (stdout, stderr):
  4244. state.TimingShow()
  4245. self.assertIn('read:', stdout.getvalue())
  4246. self.assertIn('compress:', stdout.getvalue())
  4247. def testUpdateFdtInElf(self):
  4248. """Test that we can update the devicetree in an ELF file"""
  4249. if not elf.ELF_TOOLS:
  4250. self.skipTest('Python elftools not available')
  4251. infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
  4252. outfile = os.path.join(self._indir, 'u-boot.out')
  4253. begin_sym = 'dtb_embed_begin'
  4254. end_sym = 'dtb_embed_end'
  4255. retcode = self._DoTestFile(
  4256. '060_fdt_update.dts', update_dtb=True,
  4257. update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
  4258. self.assertEqual(0, retcode)
  4259. # Check that the output file does in fact contact a dtb with the binman
  4260. # definition in the correct place
  4261. syms = elf.GetSymbolFileOffset(infile,
  4262. ['dtb_embed_begin', 'dtb_embed_end'])
  4263. data = tools.read_file(outfile)
  4264. dtb_data = data[syms['dtb_embed_begin'].offset:
  4265. syms['dtb_embed_end'].offset]
  4266. dtb = fdt.Fdt.FromData(dtb_data)
  4267. dtb.Scan()
  4268. props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
  4269. self.assertEqual({
  4270. 'image-pos': 0,
  4271. 'offset': 0,
  4272. '_testing:offset': 32,
  4273. '_testing:size': 2,
  4274. '_testing:image-pos': 32,
  4275. 'section@0/u-boot:offset': 0,
  4276. 'section@0/u-boot:size': len(U_BOOT_DATA),
  4277. 'section@0/u-boot:image-pos': 0,
  4278. 'section@0:offset': 0,
  4279. 'section@0:size': 16,
  4280. 'section@0:image-pos': 0,
  4281. 'section@1/u-boot:offset': 0,
  4282. 'section@1/u-boot:size': len(U_BOOT_DATA),
  4283. 'section@1/u-boot:image-pos': 16,
  4284. 'section@1:offset': 16,
  4285. 'section@1:size': 16,
  4286. 'section@1:image-pos': 16,
  4287. 'size': 40
  4288. }, props)
  4289. def testUpdateFdtInElfInvalid(self):
  4290. """Test that invalid args are detected with --update-fdt-in-elf"""
  4291. with self.assertRaises(ValueError) as e:
  4292. self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
  4293. self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
  4294. str(e.exception))
  4295. def testUpdateFdtInElfNoSyms(self):
  4296. """Test that missing symbols are detected with --update-fdt-in-elf"""
  4297. if not elf.ELF_TOOLS:
  4298. self.skipTest('Python elftools not available')
  4299. infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
  4300. outfile = ''
  4301. begin_sym = 'wrong_begin'
  4302. end_sym = 'wrong_end'
  4303. with self.assertRaises(ValueError) as e:
  4304. self._DoTestFile(
  4305. '060_fdt_update.dts',
  4306. update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
  4307. self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
  4308. str(e.exception))
  4309. def testUpdateFdtInElfTooSmall(self):
  4310. """Test that an over-large dtb is detected with --update-fdt-in-elf"""
  4311. if not elf.ELF_TOOLS:
  4312. self.skipTest('Python elftools not available')
  4313. infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
  4314. outfile = os.path.join(self._indir, 'u-boot.out')
  4315. begin_sym = 'dtb_embed_begin'
  4316. end_sym = 'dtb_embed_end'
  4317. with self.assertRaises(ValueError) as e:
  4318. self._DoTestFile(
  4319. '060_fdt_update.dts', update_dtb=True,
  4320. update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
  4321. self.assertRegex(
  4322. str(e.exception),
  4323. "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
  4324. def testVersion(self):
  4325. """Test we can get the binman version"""
  4326. version = '(unreleased)'
  4327. self.assertEqual(version, state.GetVersion(self._indir))
  4328. with self.assertRaises(SystemExit):
  4329. with test_util.capture_sys_output() as (_, stderr):
  4330. self._DoBinman('-V')
  4331. self.assertEqual('Binman %s\n' % version, stderr.getvalue())
  4332. # Try running the tool too, just to be safe
  4333. result = self._RunBinman('-V')
  4334. self.assertEqual('Binman %s\n' % version, result.stderr)
  4335. # Set up a version file to make sure that works
  4336. version = 'v2025.01-rc2'
  4337. tools.write_file(os.path.join(self._indir, 'version'), version,
  4338. binary=False)
  4339. self.assertEqual(version, state.GetVersion(self._indir))
  4340. def testAltFormat(self):
  4341. """Test that alternative formats can be used to extract"""
  4342. self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
  4343. try:
  4344. tmpdir, updated_fname = self._SetupImageInTmpdir()
  4345. with test_util.capture_sys_output() as (stdout, _):
  4346. self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
  4347. self.assertEqual(
  4348. '''Flag (-F) Entry type Description
  4349. fdt fdtmap Extract the devicetree blob from the fdtmap
  4350. ''',
  4351. stdout.getvalue())
  4352. dtb = os.path.join(tmpdir, 'fdt.dtb')
  4353. self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
  4354. dtb, 'fdtmap')
  4355. # Check that we can read it and it can be scanning, meaning it does
  4356. # not have a 16-byte fdtmap header
  4357. data = tools.read_file(dtb)
  4358. dtb = fdt.Fdt.FromData(data)
  4359. dtb.Scan()
  4360. # Now check u-boot which has no alt_format
  4361. fname = os.path.join(tmpdir, 'fdt.dtb')
  4362. self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
  4363. '-f', fname, 'u-boot')
  4364. data = tools.read_file(fname)
  4365. self.assertEqual(U_BOOT_DATA, data)
  4366. finally:
  4367. shutil.rmtree(tmpdir)
  4368. def testExtblobList(self):
  4369. """Test an image with an external blob list"""
  4370. data = self._DoReadFile('215_blob_ext_list.dts')
  4371. self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
  4372. def testExtblobListMissing(self):
  4373. """Test an image with a missing external blob"""
  4374. with self.assertRaises(ValueError) as e:
  4375. self._DoReadFile('216_blob_ext_list_missing.dts')
  4376. self.assertIn("Filename 'missing-file' not found in input path",
  4377. str(e.exception))
  4378. def testExtblobListMissingOk(self):
  4379. """Test an image with an missing external blob that is allowed"""
  4380. with test_util.capture_sys_output() as (stdout, stderr):
  4381. self._DoTestFile('216_blob_ext_list_missing.dts',
  4382. allow_missing=True)
  4383. err = stderr.getvalue()
  4384. self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
  4385. def testFip(self):
  4386. """Basic test of generation of an ARM Firmware Image Package (FIP)"""
  4387. data = self._DoReadFile('203_fip.dts')
  4388. hdr, fents = fip_util.decode_fip(data)
  4389. self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
  4390. self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
  4391. self.assertEqual(0x123, hdr.flags)
  4392. self.assertEqual(2, len(fents))
  4393. fent = fents[0]
  4394. self.assertEqual(
  4395. bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
  4396. 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
  4397. self.assertEqual('soc-fw', fent.fip_type)
  4398. self.assertEqual(0x88, fent.offset)
  4399. self.assertEqual(len(ATF_BL31_DATA), fent.size)
  4400. self.assertEqual(0x123456789abcdef, fent.flags)
  4401. self.assertEqual(ATF_BL31_DATA, fent.data)
  4402. self.assertEqual(True, fent.valid)
  4403. fent = fents[1]
  4404. self.assertEqual(
  4405. bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
  4406. 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
  4407. self.assertEqual('scp-fwu-cfg', fent.fip_type)
  4408. self.assertEqual(0x8c, fent.offset)
  4409. self.assertEqual(len(ATF_BL31_DATA), fent.size)
  4410. self.assertEqual(0, fent.flags)
  4411. self.assertEqual(ATF_BL2U_DATA, fent.data)
  4412. self.assertEqual(True, fent.valid)
  4413. def testFipOther(self):
  4414. """Basic FIP with something that isn't a external blob"""
  4415. data = self._DoReadFile('204_fip_other.dts')
  4416. hdr, fents = fip_util.decode_fip(data)
  4417. self.assertEqual(2, len(fents))
  4418. fent = fents[1]
  4419. self.assertEqual('rot-cert', fent.fip_type)
  4420. self.assertEqual(b'aa', fent.data)
  4421. def testFipNoType(self):
  4422. """FIP with an entry of an unknown type"""
  4423. with self.assertRaises(ValueError) as e:
  4424. self._DoReadFile('205_fip_no_type.dts')
  4425. self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
  4426. str(e.exception))
  4427. def testFipUuid(self):
  4428. """Basic FIP with a manual uuid"""
  4429. data = self._DoReadFile('206_fip_uuid.dts')
  4430. hdr, fents = fip_util.decode_fip(data)
  4431. self.assertEqual(2, len(fents))
  4432. fent = fents[1]
  4433. self.assertEqual(None, fent.fip_type)
  4434. self.assertEqual(
  4435. bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
  4436. 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
  4437. fent.uuid)
  4438. self.assertEqual(U_BOOT_DATA, fent.data)
  4439. def testFipLs(self):
  4440. """Test listing a FIP"""
  4441. data = self._DoReadFileRealDtb('207_fip_ls.dts')
  4442. hdr, fents = fip_util.decode_fip(data)
  4443. try:
  4444. tmpdir, updated_fname = self._SetupImageInTmpdir()
  4445. with test_util.capture_sys_output() as (stdout, stderr):
  4446. self._DoBinman('ls', '-i', updated_fname)
  4447. finally:
  4448. shutil.rmtree(tmpdir)
  4449. lines = stdout.getvalue().splitlines()
  4450. expected = [
  4451. 'Name Image-pos Size Entry-type Offset Uncomp-size',
  4452. '--------------------------------------------------------------',
  4453. 'image 0 2d3 section 0',
  4454. ' atf-fip 0 90 atf-fip 0',
  4455. ' soc-fw 88 4 blob-ext 88',
  4456. ' u-boot 8c 4 u-boot 8c',
  4457. ' fdtmap 90 243 fdtmap 90',
  4458. ]
  4459. self.assertEqual(expected, lines)
  4460. image = control.images['image']
  4461. entries = image.GetEntries()
  4462. fdtmap = entries['fdtmap']
  4463. fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
  4464. magic = fdtmap_data[:8]
  4465. self.assertEqual(b'_FDTMAP_', magic)
  4466. self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
  4467. fdt_data = fdtmap_data[16:]
  4468. dtb = fdt.Fdt.FromData(fdt_data)
  4469. dtb.Scan()
  4470. props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
  4471. self.assertEqual({
  4472. 'atf-fip/soc-fw:image-pos': 136,
  4473. 'atf-fip/soc-fw:offset': 136,
  4474. 'atf-fip/soc-fw:size': 4,
  4475. 'atf-fip/u-boot:image-pos': 140,
  4476. 'atf-fip/u-boot:offset': 140,
  4477. 'atf-fip/u-boot:size': 4,
  4478. 'atf-fip:image-pos': 0,
  4479. 'atf-fip:offset': 0,
  4480. 'atf-fip:size': 144,
  4481. 'image-pos': 0,
  4482. 'offset': 0,
  4483. 'fdtmap:image-pos': fdtmap.image_pos,
  4484. 'fdtmap:offset': fdtmap.offset,
  4485. 'fdtmap:size': len(fdtmap_data),
  4486. 'size': len(data),
  4487. }, props)
  4488. def testFipExtractOneEntry(self):
  4489. """Test extracting a single entry fron an FIP"""
  4490. self._DoReadFileRealDtb('207_fip_ls.dts')
  4491. image_fname = tools.get_output_filename('image.bin')
  4492. fname = os.path.join(self._indir, 'output.extact')
  4493. control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
  4494. data = tools.read_file(fname)
  4495. self.assertEqual(U_BOOT_DATA, data)
  4496. def testFipReplace(self):
  4497. """Test replacing a single file in a FIP"""
  4498. expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
  4499. data = self._DoReadFileRealDtb('208_fip_replace.dts')
  4500. updated_fname = tools.get_output_filename('image-updated.bin')
  4501. tools.write_file(updated_fname, data)
  4502. entry_name = 'atf-fip/u-boot'
  4503. control.WriteEntry(updated_fname, entry_name, expected,
  4504. allow_resize=True)
  4505. actual = control.ReadEntry(updated_fname, entry_name)
  4506. self.assertEqual(expected, actual)
  4507. new_data = tools.read_file(updated_fname)
  4508. hdr, fents = fip_util.decode_fip(new_data)
  4509. self.assertEqual(2, len(fents))
  4510. # Check that the FIP entry is updated
  4511. fent = fents[1]
  4512. self.assertEqual(0x8c, fent.offset)
  4513. self.assertEqual(len(expected), fent.size)
  4514. self.assertEqual(0, fent.flags)
  4515. self.assertEqual(expected, fent.data)
  4516. self.assertEqual(True, fent.valid)
  4517. def testFipMissing(self):
  4518. with test_util.capture_sys_output() as (stdout, stderr):
  4519. self._DoTestFile('209_fip_missing.dts', allow_missing=True)
  4520. err = stderr.getvalue()
  4521. self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
  4522. def testFipSize(self):
  4523. """Test a FIP with a size property"""
  4524. data = self._DoReadFile('210_fip_size.dts')
  4525. self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
  4526. hdr, fents = fip_util.decode_fip(data)
  4527. self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
  4528. self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
  4529. self.assertEqual(1, len(fents))
  4530. fent = fents[0]
  4531. self.assertEqual('soc-fw', fent.fip_type)
  4532. self.assertEqual(0x60, fent.offset)
  4533. self.assertEqual(len(ATF_BL31_DATA), fent.size)
  4534. self.assertEqual(ATF_BL31_DATA, fent.data)
  4535. self.assertEqual(True, fent.valid)
  4536. rest = data[0x60 + len(ATF_BL31_DATA):0x100]
  4537. self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
  4538. def testFipBadAlign(self):
  4539. """Test that an invalid alignment value in a FIP is detected"""
  4540. with self.assertRaises(ValueError) as e:
  4541. self._DoTestFile('211_fip_bad_align.dts')
  4542. self.assertIn(
  4543. "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
  4544. str(e.exception))
  4545. def testFipCollection(self):
  4546. """Test using a FIP in a collection"""
  4547. data = self._DoReadFile('212_fip_collection.dts')
  4548. entry1 = control.images['image'].GetEntries()['collection']
  4549. data1 = data[:entry1.size]
  4550. hdr1, fents2 = fip_util.decode_fip(data1)
  4551. entry2 = control.images['image'].GetEntries()['atf-fip']
  4552. data2 = data[entry2.offset:entry2.offset + entry2.size]
  4553. hdr1, fents2 = fip_util.decode_fip(data2)
  4554. # The 'collection' entry should have U-Boot included at the end
  4555. self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
  4556. self.assertEqual(data1, data2 + U_BOOT_DATA)
  4557. self.assertEqual(U_BOOT_DATA, data1[-4:])
  4558. # There should be a U-Boot after the final FIP
  4559. self.assertEqual(U_BOOT_DATA, data[-4:])
  4560. def testFakeBlob(self):
  4561. """Test handling of faking an external blob"""
  4562. with test_util.capture_sys_output() as (stdout, stderr):
  4563. self._DoTestFile('217_fake_blob.dts', allow_missing=True,
  4564. allow_fake_blobs=True)
  4565. err = stderr.getvalue()
  4566. self.assertRegex(
  4567. err,
  4568. "Image '.*' has faked external blobs and is non-functional: .*")
  4569. def testExtblobListFaked(self):
  4570. """Test an extblob with missing external blob that are faked"""
  4571. with test_util.capture_sys_output() as (stdout, stderr):
  4572. self._DoTestFile('216_blob_ext_list_missing.dts',
  4573. allow_fake_blobs=True)
  4574. err = stderr.getvalue()
  4575. self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
  4576. def testListBintools(self):
  4577. args = ['tool', '--list']
  4578. with test_util.capture_sys_output() as (stdout, _):
  4579. self._DoBinman(*args)
  4580. out = stdout.getvalue().splitlines()
  4581. self.assertTrue(len(out) >= 2)
  4582. def testFetchBintools(self):
  4583. def fail_download(url):
  4584. """Take the tools.download() function by raising an exception"""
  4585. raise urllib.error.URLError('my error')
  4586. args = ['tool']
  4587. with self.assertRaises(ValueError) as e:
  4588. self._DoBinman(*args)
  4589. self.assertIn("Invalid arguments to 'tool' subcommand",
  4590. str(e.exception))
  4591. args = ['tool', '--fetch']
  4592. with self.assertRaises(ValueError) as e:
  4593. self._DoBinman(*args)
  4594. self.assertIn('Please specify bintools to fetch', str(e.exception))
  4595. args = ['tool', '--fetch', '_testing']
  4596. with unittest.mock.patch.object(tools, 'download',
  4597. side_effect=fail_download):
  4598. with test_util.capture_sys_output() as (stdout, _):
  4599. self._DoBinman(*args)
  4600. self.assertIn('failed to fetch with all methods', stdout.getvalue())
  4601. def testBintoolDocs(self):
  4602. """Test for creation of bintool documentation"""
  4603. with test_util.capture_sys_output() as (stdout, stderr):
  4604. control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
  4605. self.assertTrue(len(stdout.getvalue()) > 0)
  4606. def testBintoolDocsMissing(self):
  4607. """Test handling of missing bintool documentation"""
  4608. with self.assertRaises(ValueError) as e:
  4609. with test_util.capture_sys_output() as (stdout, stderr):
  4610. control.write_bintool_docs(
  4611. control.bintool.Bintool.get_tool_list(), 'mkimage')
  4612. self.assertIn('Documentation is missing for modules: mkimage',
  4613. str(e.exception))
  4614. def testListWithGenNode(self):
  4615. """Check handling of an FDT map when the section cannot be found"""
  4616. entry_args = {
  4617. 'of-list': 'test-fdt1 test-fdt2',
  4618. }
  4619. data = self._DoReadFileDtb(
  4620. '219_fit_gennode.dts',
  4621. entry_args=entry_args,
  4622. use_real_dtb=True,
  4623. extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
  4624. try:
  4625. tmpdir, updated_fname = self._SetupImageInTmpdir()
  4626. with test_util.capture_sys_output() as (stdout, stderr):
  4627. self._RunBinman('ls', '-i', updated_fname)
  4628. finally:
  4629. shutil.rmtree(tmpdir)
  4630. def testFitSubentryUsesBintool(self):
  4631. """Test that binman FIT subentries can use bintools"""
  4632. command.test_result = self._HandleGbbCommand
  4633. entry_args = {
  4634. 'keydir': 'devkeys',
  4635. 'bmpblk': 'bmpblk.bin',
  4636. }
  4637. data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
  4638. entry_args=entry_args)
  4639. expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
  4640. tools.get_bytes(0, 0x2180 - 16))
  4641. self.assertIn(expected, data)
  4642. def testFitSubentryMissingBintool(self):
  4643. """Test that binman reports missing bintools for FIT subentries"""
  4644. entry_args = {
  4645. 'keydir': 'devkeys',
  4646. }
  4647. with test_util.capture_sys_output() as (_, stderr):
  4648. self._DoTestFile('220_fit_subentry_bintool.dts',
  4649. force_missing_bintools='futility', entry_args=entry_args)
  4650. err = stderr.getvalue()
  4651. self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
  4652. def testFitSubentryHashSubnode(self):
  4653. """Test an image with a FIT inside"""
  4654. self._SetupSplElf()
  4655. data, _, _, out_dtb_name = self._DoReadFileDtb(
  4656. '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
  4657. mkimage_dtb = fdt.Fdt.FromData(data)
  4658. mkimage_dtb.Scan()
  4659. binman_dtb = fdt.Fdt(out_dtb_name)
  4660. binman_dtb.Scan()
  4661. # Check that binman didn't add hash values
  4662. fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
  4663. self.assertNotIn('value', fnode.props)
  4664. fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
  4665. self.assertNotIn('value', fnode.props)
  4666. # Check that mkimage added hash values
  4667. fnode = mkimage_dtb.GetNode('/images/kernel/hash')
  4668. self.assertIn('value', fnode.props)
  4669. fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
  4670. self.assertIn('value', fnode.props)
  4671. def testPackTeeOs(self):
  4672. """Test that an image with an TEE binary can be created"""
  4673. data = self._DoReadFile('222_tee_os.dts')
  4674. self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
  4675. def testFitFdtOper(self):
  4676. """Check handling of a specified FIT operation"""
  4677. entry_args = {
  4678. 'of-list': 'test-fdt1 test-fdt2',
  4679. 'default-dt': 'test-fdt2',
  4680. }
  4681. self._DoReadFileDtb(
  4682. '223_fit_fdt_oper.dts',
  4683. entry_args=entry_args,
  4684. extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
  4685. def testFitFdtBadOper(self):
  4686. """Check handling of an FDT map when the section cannot be found"""
  4687. with self.assertRaises(ValueError) as exc:
  4688. self._DoReadFileDtb('224_fit_bad_oper.dts')
  4689. self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
  4690. str(exc.exception))
  4691. def test_uses_expand_size(self):
  4692. """Test that the 'expand-size' property cannot be used anymore"""
  4693. with self.assertRaises(ValueError) as e:
  4694. data = self._DoReadFile('225_expand_size_bad.dts')
  4695. self.assertIn(
  4696. "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
  4697. str(e.exception))
  4698. def testFitSplitElf(self):
  4699. """Test an image with an FIT with an split-elf operation"""
  4700. if not elf.ELF_TOOLS:
  4701. self.skipTest('Python elftools not available')
  4702. entry_args = {
  4703. 'of-list': 'test-fdt1 test-fdt2',
  4704. 'default-dt': 'test-fdt2',
  4705. 'atf-bl31-path': 'bl31.elf',
  4706. 'tee-os-path': 'tee.elf',
  4707. }
  4708. test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
  4709. data = self._DoReadFileDtb(
  4710. '226_fit_split_elf.dts',
  4711. entry_args=entry_args,
  4712. extra_indirs=[test_subdir])[0]
  4713. self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
  4714. fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
  4715. base_keys = {'description', 'type', 'arch', 'os', 'compression',
  4716. 'data', 'load'}
  4717. dtb = fdt.Fdt.FromData(fit_data)
  4718. dtb.Scan()
  4719. elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
  4720. segments, entry = elf.read_loadable_segments(elf_data)
  4721. # We assume there are two segments
  4722. self.assertEquals(2, len(segments))
  4723. atf1 = dtb.GetNode('/images/atf-1')
  4724. _, start, data = segments[0]
  4725. self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
  4726. self.assertEqual(entry,
  4727. fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
  4728. self.assertEqual(start,
  4729. fdt_util.fdt32_to_cpu(atf1.props['load'].value))
  4730. self.assertEqual(data, atf1.props['data'].bytes)
  4731. hash_node = atf1.FindNode('hash')
  4732. self.assertIsNotNone(hash_node)
  4733. self.assertEqual({'algo', 'value'}, hash_node.props.keys())
  4734. atf2 = dtb.GetNode('/images/atf-2')
  4735. self.assertEqual(base_keys, atf2.props.keys())
  4736. _, start, data = segments[1]
  4737. self.assertEqual(start,
  4738. fdt_util.fdt32_to_cpu(atf2.props['load'].value))
  4739. self.assertEqual(data, atf2.props['data'].bytes)
  4740. hash_node = atf2.FindNode('hash')
  4741. self.assertIsNotNone(hash_node)
  4742. self.assertEqual({'algo', 'value'}, hash_node.props.keys())
  4743. hash_node = dtb.GetNode('/images/tee-1/hash-1')
  4744. self.assertIsNotNone(hash_node)
  4745. self.assertEqual({'algo', 'value'}, hash_node.props.keys())
  4746. conf = dtb.GetNode('/configurations')
  4747. self.assertEqual({'default'}, conf.props.keys())
  4748. for subnode in conf.subnodes:
  4749. self.assertEqual({'description', 'fdt', 'loadables'},
  4750. subnode.props.keys())
  4751. self.assertEqual(
  4752. ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
  4753. fdt_util.GetStringList(subnode, 'loadables'))
  4754. def _check_bad_fit(self, dts):
  4755. """Check a bad FIT
  4756. This runs with the given dts and returns the assertion raised
  4757. Args:
  4758. dts (str): dts filename to use
  4759. Returns:
  4760. str: Assertion string raised
  4761. """
  4762. entry_args = {
  4763. 'of-list': 'test-fdt1 test-fdt2',
  4764. 'default-dt': 'test-fdt2',
  4765. 'atf-bl31-path': 'bl31.elf',
  4766. 'tee-os-path': 'tee.elf',
  4767. }
  4768. test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
  4769. with self.assertRaises(ValueError) as exc:
  4770. self._DoReadFileDtb(dts, entry_args=entry_args,
  4771. extra_indirs=[test_subdir])[0]
  4772. return str(exc.exception)
  4773. def testFitSplitElfBadElf(self):
  4774. """Test a FIT split-elf operation with an invalid ELF file"""
  4775. if not elf.ELF_TOOLS:
  4776. self.skipTest('Python elftools not available')
  4777. TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
  4778. entry_args = {
  4779. 'of-list': 'test-fdt1 test-fdt2',
  4780. 'default-dt': 'test-fdt2',
  4781. 'atf-bl31-path': 'bad.elf',
  4782. 'tee-os-path': 'tee.elf',
  4783. }
  4784. test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
  4785. with self.assertRaises(ValueError) as exc:
  4786. self._DoReadFileDtb(
  4787. '226_fit_split_elf.dts',
  4788. entry_args=entry_args,
  4789. extra_indirs=[test_subdir])[0]
  4790. self.assertIn(
  4791. "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
  4792. str(exc.exception))
  4793. def checkFitSplitElf(self, **kwargs):
  4794. """Test an split-elf FIT with a missing ELF file
  4795. Args:
  4796. kwargs (dict of str): Arguments to pass to _DoTestFile()
  4797. Returns:
  4798. tuple:
  4799. str: stdout result
  4800. str: stderr result
  4801. """
  4802. entry_args = {
  4803. 'of-list': 'test-fdt1 test-fdt2',
  4804. 'default-dt': 'test-fdt2',
  4805. 'atf-bl31-path': 'bl31.elf',
  4806. 'tee-os-path': 'missing.elf',
  4807. }
  4808. test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
  4809. with test_util.capture_sys_output() as (stdout, stderr):
  4810. self._DoTestFile(
  4811. '226_fit_split_elf.dts', entry_args=entry_args,
  4812. extra_indirs=[test_subdir], verbosity=3, **kwargs)
  4813. out = stdout.getvalue()
  4814. err = stderr.getvalue()
  4815. return out, err
  4816. def testFitSplitElfBadDirective(self):
  4817. """Test a FIT split-elf invalid fit,xxx directive in an image node"""
  4818. if not elf.ELF_TOOLS:
  4819. self.skipTest('Python elftools not available')
  4820. err = self._check_bad_fit('227_fit_bad_dir.dts')
  4821. self.assertIn(
  4822. "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
  4823. err)
  4824. def testFitSplitElfBadDirectiveConfig(self):
  4825. """Test a FIT split-elf with invalid fit,xxx directive in config"""
  4826. if not elf.ELF_TOOLS:
  4827. self.skipTest('Python elftools not available')
  4828. err = self._check_bad_fit('228_fit_bad_dir_config.dts')
  4829. self.assertEqual(
  4830. "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
  4831. err)
  4832. def testFitSplitElfMissing(self):
  4833. """Test an split-elf FIT with a missing ELF file"""
  4834. if not elf.ELF_TOOLS:
  4835. self.skipTest('Python elftools not available')
  4836. out, err = self.checkFitSplitElf(allow_missing=True)
  4837. self.assertRegex(
  4838. err,
  4839. "Image '.*' is missing external blobs and is non-functional: .*")
  4840. self.assertNotRegex(out, '.*Faked blob.*')
  4841. fname = tools.get_output_filename('binman-fake/missing.elf')
  4842. self.assertFalse(os.path.exists(fname))
  4843. def testFitSplitElfFaked(self):
  4844. """Test an split-elf FIT with faked ELF file"""
  4845. if not elf.ELF_TOOLS:
  4846. self.skipTest('Python elftools not available')
  4847. out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
  4848. self.assertRegex(
  4849. err,
  4850. "Image '.*' is missing external blobs and is non-functional: .*")
  4851. self.assertRegex(
  4852. out,
  4853. "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
  4854. fname = tools.get_output_filename('binman-fake/missing.elf')
  4855. self.assertTrue(os.path.exists(fname))
  4856. def testMkimageMissingBlob(self):
  4857. """Test using mkimage to build an image"""
  4858. with test_util.capture_sys_output() as (stdout, stderr):
  4859. self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
  4860. allow_fake_blobs=True)
  4861. err = stderr.getvalue()
  4862. self.assertRegex(
  4863. err,
  4864. "Image '.*' has faked external blobs and is non-functional: .*")
  4865. def testPreLoad(self):
  4866. """Test an image with a pre-load header"""
  4867. entry_args = {
  4868. 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
  4869. }
  4870. data = self._DoReadFileDtb(
  4871. '230_pre_load.dts', entry_args=entry_args,
  4872. extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
  4873. self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
  4874. self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
  4875. self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
  4876. def testPreLoadNoKey(self):
  4877. """Test an image with a pre-load heade0r with missing key"""
  4878. with self.assertRaises(FileNotFoundError) as exc:
  4879. self._DoReadFile('230_pre_load.dts')
  4880. self.assertIn("No such file or directory: 'dev.key'",
  4881. str(exc.exception))
  4882. def testPreLoadPkcs(self):
  4883. """Test an image with a pre-load header with padding pkcs"""
  4884. entry_args = {
  4885. 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
  4886. }
  4887. data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
  4888. entry_args=entry_args)[0]
  4889. self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
  4890. self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
  4891. self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
  4892. def testPreLoadPss(self):
  4893. """Test an image with a pre-load header with padding pss"""
  4894. entry_args = {
  4895. 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
  4896. }
  4897. data = self._DoReadFileDtb('232_pre_load_pss.dts',
  4898. entry_args=entry_args)[0]
  4899. self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
  4900. self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
  4901. self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
  4902. def testPreLoadInvalidPadding(self):
  4903. """Test an image with a pre-load header with an invalid padding"""
  4904. entry_args = {
  4905. 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
  4906. }
  4907. with self.assertRaises(ValueError) as e:
  4908. self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
  4909. entry_args=entry_args)
  4910. def testPreLoadInvalidSha(self):
  4911. """Test an image with a pre-load header with an invalid hash"""
  4912. entry_args = {
  4913. 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
  4914. }
  4915. with self.assertRaises(ValueError) as e:
  4916. self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
  4917. entry_args=entry_args)
  4918. def testPreLoadInvalidAlgo(self):
  4919. """Test an image with a pre-load header with an invalid algo"""
  4920. with self.assertRaises(ValueError) as e:
  4921. data = self._DoReadFile('235_pre_load_invalid_algo.dts')
  4922. def testPreLoadInvalidKey(self):
  4923. """Test an image with a pre-load header with an invalid key"""
  4924. entry_args = {
  4925. 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
  4926. }
  4927. with self.assertRaises(ValueError) as e:
  4928. data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
  4929. entry_args=entry_args)
  4930. def _CheckSafeUniqueNames(self, *images):
  4931. """Check all entries of given images for unsafe unique names"""
  4932. for image in images:
  4933. entries = {}
  4934. image._CollectEntries(entries, {}, image)
  4935. for entry in entries.values():
  4936. uniq = entry.GetUniqueName()
  4937. # Used as part of a filename, so must not be absolute paths.
  4938. self.assertFalse(os.path.isabs(uniq))
  4939. def testSafeUniqueNames(self):
  4940. """Test entry unique names are safe in single image configuration"""
  4941. data = self._DoReadFileRealDtb('237_unique_names.dts')
  4942. orig_image = control.images['image']
  4943. image_fname = tools.get_output_filename('image.bin')
  4944. image = Image.FromFile(image_fname)
  4945. self._CheckSafeUniqueNames(orig_image, image)
  4946. def testSafeUniqueNamesMulti(self):
  4947. """Test entry unique names are safe with multiple images"""
  4948. data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
  4949. orig_image = control.images['image']
  4950. image_fname = tools.get_output_filename('image.bin')
  4951. image = Image.FromFile(image_fname)
  4952. self._CheckSafeUniqueNames(orig_image, image)
  4953. def testReplaceCmdWithBintool(self):
  4954. """Test replacing an entry that needs a bintool to pack"""
  4955. data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
  4956. expected = U_BOOT_DATA + b'aa'
  4957. self.assertEqual(expected, data[:len(expected)])
  4958. try:
  4959. tmpdir, updated_fname = self._SetupImageInTmpdir()
  4960. fname = os.path.join(tmpdir, 'update-testing.bin')
  4961. tools.write_file(fname, b'zz')
  4962. self._DoBinman('replace', '-i', updated_fname,
  4963. '_testing', '-f', fname)
  4964. data = tools.read_file(updated_fname)
  4965. expected = U_BOOT_DATA + b'zz'
  4966. self.assertEqual(expected, data[:len(expected)])
  4967. finally:
  4968. shutil.rmtree(tmpdir)
  4969. def testReplaceCmdOtherWithBintool(self):
  4970. """Test replacing an entry when another needs a bintool to pack"""
  4971. data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
  4972. expected = U_BOOT_DATA + b'aa'
  4973. self.assertEqual(expected, data[:len(expected)])
  4974. try:
  4975. tmpdir, updated_fname = self._SetupImageInTmpdir()
  4976. fname = os.path.join(tmpdir, 'update-u-boot.bin')
  4977. tools.write_file(fname, b'x' * len(U_BOOT_DATA))
  4978. self._DoBinman('replace', '-i', updated_fname,
  4979. 'u-boot', '-f', fname)
  4980. data = tools.read_file(updated_fname)
  4981. expected = b'x' * len(U_BOOT_DATA) + b'aa'
  4982. self.assertEqual(expected, data[:len(expected)])
  4983. finally:
  4984. shutil.rmtree(tmpdir)
  4985. def testReplaceResizeNoRepackSameSize(self):
  4986. """Test replacing entries with same-size data without repacking"""
  4987. expected = b'x' * len(U_BOOT_DATA)
  4988. data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
  4989. self.assertEqual(expected, data)
  4990. path, fdtmap = state.GetFdtContents('fdtmap')
  4991. self.assertIsNotNone(path)
  4992. self.assertEqual(expected_fdtmap, fdtmap)
  4993. def testReplaceResizeNoRepackSmallerSize(self):
  4994. """Test replacing entries with smaller-size data without repacking"""
  4995. new_data = b'x'
  4996. data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
  4997. expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
  4998. self.assertEqual(expected, data)
  4999. path, fdtmap = state.GetFdtContents('fdtmap')
  5000. self.assertIsNotNone(path)
  5001. self.assertEqual(expected_fdtmap, fdtmap)
  5002. def testExtractFit(self):
  5003. """Test extracting a FIT section"""
  5004. self._DoReadFileRealDtb('240_fit_extract_replace.dts')
  5005. image_fname = tools.get_output_filename('image.bin')
  5006. fit_data = control.ReadEntry(image_fname, 'fit')
  5007. fit = fdt.Fdt.FromData(fit_data)
  5008. fit.Scan()
  5009. # Check subentry data inside the extracted fit
  5010. for node_path, expected in [
  5011. ('/images/kernel', U_BOOT_DATA),
  5012. ('/images/fdt-1', U_BOOT_NODTB_DATA),
  5013. ('/images/scr-1', COMPRESS_DATA),
  5014. ]:
  5015. node = fit.GetNode(node_path)
  5016. data = fit.GetProps(node)['data'].bytes
  5017. self.assertEqual(expected, data)
  5018. def testExtractFitSubentries(self):
  5019. """Test extracting FIT section subentries"""
  5020. self._DoReadFileRealDtb('240_fit_extract_replace.dts')
  5021. image_fname = tools.get_output_filename('image.bin')
  5022. for entry_path, expected in [
  5023. ('fit/kernel', U_BOOT_DATA),
  5024. ('fit/kernel/u-boot', U_BOOT_DATA),
  5025. ('fit/fdt-1', U_BOOT_NODTB_DATA),
  5026. ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
  5027. ('fit/scr-1', COMPRESS_DATA),
  5028. ('fit/scr-1/blob', COMPRESS_DATA),
  5029. ]:
  5030. data = control.ReadEntry(image_fname, entry_path)
  5031. self.assertEqual(expected, data)
  5032. def testReplaceFitSubentryLeafSameSize(self):
  5033. """Test replacing a FIT leaf subentry with same-size data"""
  5034. new_data = b'x' * len(U_BOOT_DATA)
  5035. data, expected_fdtmap, _ = self._RunReplaceCmd(
  5036. 'fit/kernel/u-boot', new_data,
  5037. dts='240_fit_extract_replace.dts')
  5038. self.assertEqual(new_data, data)
  5039. path, fdtmap = state.GetFdtContents('fdtmap')
  5040. self.assertIsNotNone(path)
  5041. self.assertEqual(expected_fdtmap, fdtmap)
  5042. def testReplaceFitSubentryLeafBiggerSize(self):
  5043. """Test replacing a FIT leaf subentry with bigger-size data"""
  5044. new_data = b'ub' * len(U_BOOT_NODTB_DATA)
  5045. data, expected_fdtmap, _ = self._RunReplaceCmd(
  5046. 'fit/fdt-1/u-boot-nodtb', new_data,
  5047. dts='240_fit_extract_replace.dts')
  5048. self.assertEqual(new_data, data)
  5049. # Will be repacked, so fdtmap must change
  5050. path, fdtmap = state.GetFdtContents('fdtmap')
  5051. self.assertIsNotNone(path)
  5052. self.assertNotEqual(expected_fdtmap, fdtmap)
  5053. def testReplaceFitSubentryLeafSmallerSize(self):
  5054. """Test replacing a FIT leaf subentry with smaller-size data"""
  5055. new_data = b'x'
  5056. expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
  5057. data, expected_fdtmap, _ = self._RunReplaceCmd(
  5058. 'fit/fdt-1/u-boot-nodtb', new_data,
  5059. dts='240_fit_extract_replace.dts')
  5060. self.assertEqual(expected, data)
  5061. path, fdtmap = state.GetFdtContents('fdtmap')
  5062. self.assertIsNotNone(path)
  5063. self.assertEqual(expected_fdtmap, fdtmap)
  5064. def testReplaceSectionSimple(self):
  5065. """Test replacing a simple section with same-sized data"""
  5066. new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
  5067. data, expected_fdtmap, image = self._RunReplaceCmd('section',
  5068. new_data, dts='241_replace_section_simple.dts')
  5069. self.assertEqual(new_data, data)
  5070. entries = image.GetEntries()
  5071. self.assertIn('section', entries)
  5072. entry = entries['section']
  5073. self.assertEqual(len(new_data), entry.size)
  5074. def testReplaceSectionLarger(self):
  5075. """Test replacing a simple section with larger data"""
  5076. new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
  5077. data, expected_fdtmap, image = self._RunReplaceCmd('section',
  5078. new_data, dts='241_replace_section_simple.dts')
  5079. self.assertEqual(new_data, data)
  5080. entries = image.GetEntries()
  5081. self.assertIn('section', entries)
  5082. entry = entries['section']
  5083. self.assertEqual(len(new_data), entry.size)
  5084. fentry = entries['fdtmap']
  5085. self.assertEqual(entry.offset + entry.size, fentry.offset)
  5086. def testReplaceSectionSmaller(self):
  5087. """Test replacing a simple section with smaller data"""
  5088. new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
  5089. data, expected_fdtmap, image = self._RunReplaceCmd('section',
  5090. new_data, dts='241_replace_section_simple.dts')
  5091. self.assertEqual(new_data, data)
  5092. # The new size is the same as the old, just with a pad byte at the end
  5093. entries = image.GetEntries()
  5094. self.assertIn('section', entries)
  5095. entry = entries['section']
  5096. self.assertEqual(len(new_data), entry.size)
  5097. def testReplaceSectionSmallerAllow(self):
  5098. """Test failing to replace a simple section with smaller data"""
  5099. new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
  5100. try:
  5101. state.SetAllowEntryContraction(True)
  5102. with self.assertRaises(ValueError) as exc:
  5103. self._RunReplaceCmd('section', new_data,
  5104. dts='241_replace_section_simple.dts')
  5105. finally:
  5106. state.SetAllowEntryContraction(False)
  5107. # Since we have no information about the position of things within the
  5108. # section, we cannot adjust the position of /section-u-boot so it ends
  5109. # up outside the section
  5110. self.assertIn(
  5111. "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
  5112. "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
  5113. str(exc.exception))
  5114. def testMkimageImagename(self):
  5115. """Test using mkimage with -n holding the data too"""
  5116. self._SetupSplElf()
  5117. data = self._DoReadFile('242_mkimage_name.dts')
  5118. # Check that the data appears in the file somewhere
  5119. self.assertIn(U_BOOT_SPL_DATA, data)
  5120. # Get struct legacy_img_hdr -> ih_name
  5121. name = data[0x20:0x40]
  5122. # Build the filename that we expect to be placed in there, by virtue of
  5123. # the -n paraameter
  5124. expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
  5125. # Check that the image name is set to the temporary filename used
  5126. self.assertEqual(expect.encode('utf-8')[:0x20], name)
  5127. def testMkimageImage(self):
  5128. """Test using mkimage with -n holding the data too"""
  5129. self._SetupSplElf()
  5130. data = self._DoReadFile('243_mkimage_image.dts')
  5131. # Check that the data appears in the file somewhere
  5132. self.assertIn(U_BOOT_SPL_DATA, data)
  5133. # Get struct legacy_img_hdr -> ih_name
  5134. name = data[0x20:0x40]
  5135. # Build the filename that we expect to be placed in there, by virtue of
  5136. # the -n paraameter
  5137. expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
  5138. # Check that the image name is set to the temporary filename used
  5139. self.assertEqual(expect.encode('utf-8')[:0x20], name)
  5140. # Check the corect data is in the imagename file
  5141. self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
  5142. def testMkimageImageNoContent(self):
  5143. """Test using mkimage with -n and no data"""
  5144. self._SetupSplElf()
  5145. with self.assertRaises(ValueError) as exc:
  5146. self._DoReadFile('244_mkimage_image_no_content.dts')
  5147. self.assertIn('Could not complete processing of contents',
  5148. str(exc.exception))
  5149. def testMkimageImageBad(self):
  5150. """Test using mkimage with imagename node and data-to-imagename"""
  5151. self._SetupSplElf()
  5152. with self.assertRaises(ValueError) as exc:
  5153. self._DoReadFile('245_mkimage_image_bad.dts')
  5154. self.assertIn('Cannot use both imagename node and data-to-imagename',
  5155. str(exc.exception))
  5156. def testCollectionOther(self):
  5157. """Test a collection where the data comes from another section"""
  5158. data = self._DoReadFile('246_collection_other.dts')
  5159. self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
  5160. tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
  5161. tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
  5162. data)
  5163. def testMkimageCollection(self):
  5164. """Test using a collection referring to an entry in a mkimage entry"""
  5165. self._SetupSplElf()
  5166. data = self._DoReadFile('247_mkimage_coll.dts')
  5167. expect = U_BOOT_SPL_DATA + U_BOOT_DATA
  5168. self.assertEqual(expect, data[:len(expect)])
  5169. def testCompressDtbPrependInvalid(self):
  5170. """Test that invalid header is detected"""
  5171. with self.assertRaises(ValueError) as e:
  5172. self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
  5173. self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
  5174. "'u-boot-dtb': 'invalid'", str(e.exception))
  5175. def testCompressDtbPrependLength(self):
  5176. """Test that compress with length header works as expected"""
  5177. data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
  5178. image = control.images['image']
  5179. entries = image.GetEntries()
  5180. self.assertIn('u-boot-dtb', entries)
  5181. u_boot_dtb = entries['u-boot-dtb']
  5182. self.assertIn('fdtmap', entries)
  5183. fdtmap = entries['fdtmap']
  5184. image_fname = tools.get_output_filename('image.bin')
  5185. orig = control.ReadEntry(image_fname, 'u-boot-dtb')
  5186. dtb = fdt.Fdt.FromData(orig)
  5187. dtb.Scan()
  5188. props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
  5189. expected = {
  5190. 'u-boot:size': len(U_BOOT_DATA),
  5191. 'u-boot-dtb:uncomp-size': len(orig),
  5192. 'u-boot-dtb:size': u_boot_dtb.size,
  5193. 'fdtmap:size': fdtmap.size,
  5194. 'size': len(data),
  5195. }
  5196. self.assertEqual(expected, props)
  5197. # Check implementation
  5198. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  5199. rest = data[len(U_BOOT_DATA):]
  5200. comp_data_len = struct.unpack('<I', rest[:4])[0]
  5201. comp_data = rest[4:4 + comp_data_len]
  5202. orig2 = self._decompress(comp_data)
  5203. self.assertEqual(orig, orig2)
  5204. def testInvalidCompress(self):
  5205. """Test that invalid compress algorithm is detected"""
  5206. with self.assertRaises(ValueError) as e:
  5207. self._DoTestFile('250_compress_dtb_invalid.dts')
  5208. self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
  5209. def testCompUtilCompressions(self):
  5210. """Test compression algorithms"""
  5211. for bintool in self.comp_bintools.values():
  5212. self._CheckBintool(bintool)
  5213. data = bintool.compress(COMPRESS_DATA)
  5214. self.assertNotEqual(COMPRESS_DATA, data)
  5215. orig = bintool.decompress(data)
  5216. self.assertEquals(COMPRESS_DATA, orig)
  5217. def testCompUtilVersions(self):
  5218. """Test tool version of compression algorithms"""
  5219. for bintool in self.comp_bintools.values():
  5220. self._CheckBintool(bintool)
  5221. version = bintool.version()
  5222. self.assertRegex(version, '^v?[0-9]+[0-9.]*')
  5223. def testCompUtilPadding(self):
  5224. """Test padding of compression algorithms"""
  5225. # Skip zstd because it doesn't support padding
  5226. for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
  5227. self._CheckBintool(bintool)
  5228. data = bintool.compress(COMPRESS_DATA)
  5229. self.assertNotEqual(COMPRESS_DATA, data)
  5230. data += tools.get_bytes(0, 64)
  5231. orig = bintool.decompress(data)
  5232. self.assertEquals(COMPRESS_DATA, orig)
  5233. def testCompressDtbZstd(self):
  5234. """Test that zstd compress of device-tree files failed"""
  5235. with self.assertRaises(ValueError) as e:
  5236. self._DoTestFile('251_compress_dtb_zstd.dts')
  5237. self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
  5238. "requires a length header", str(e.exception))
  5239. def testMkimageMultipleDataFiles(self):
  5240. """Test passing multiple files to mkimage in a mkimage entry"""
  5241. self._SetupSplElf()
  5242. self._SetupTplElf()
  5243. data = self._DoReadFile('252_mkimage_mult_data.dts')
  5244. # Size of files are packed in their 4B big-endian format
  5245. expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
  5246. expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
  5247. # Size info is always followed by a 4B zero value.
  5248. expect += tools.get_bytes(0, 4)
  5249. expect += U_BOOT_TPL_DATA
  5250. # All but last files are 4B-aligned
  5251. align_pad = len(U_BOOT_TPL_DATA) % 4
  5252. if align_pad:
  5253. expect += tools.get_bytes(0, align_pad)
  5254. expect += U_BOOT_SPL_DATA
  5255. self.assertEqual(expect, data[-len(expect):])
  5256. def testMkimageMultipleExpanded(self):
  5257. """Test passing multiple files to mkimage in a mkimage entry"""
  5258. self._SetupSplElf()
  5259. self._SetupTplElf()
  5260. entry_args = {
  5261. 'spl-bss-pad': 'y',
  5262. 'spl-dtb': 'y',
  5263. }
  5264. data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
  5265. use_expanded=True, entry_args=entry_args)[0]
  5266. pad_len = 10
  5267. tpl_expect = U_BOOT_TPL_DATA
  5268. spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
  5269. spl_expect += U_BOOT_SPL_DTB_DATA
  5270. content = data[0x40:]
  5271. lens = struct.unpack('>III', content[:12])
  5272. # Size of files are packed in their 4B big-endian format
  5273. # Size info is always followed by a 4B zero value.
  5274. self.assertEqual(len(tpl_expect), lens[0])
  5275. self.assertEqual(len(spl_expect), lens[1])
  5276. self.assertEqual(0, lens[2])
  5277. rest = content[12:]
  5278. self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
  5279. rest = rest[len(tpl_expect):]
  5280. align_pad = len(tpl_expect) % 4
  5281. self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
  5282. rest = rest[align_pad:]
  5283. self.assertEqual(spl_expect, rest)
  5284. def testMkimageMultipleNoContent(self):
  5285. """Test passing multiple data files to mkimage with one data file having no content"""
  5286. self._SetupSplElf()
  5287. with self.assertRaises(ValueError) as exc:
  5288. self._DoReadFile('253_mkimage_mult_no_content.dts')
  5289. self.assertIn('Could not complete processing of contents',
  5290. str(exc.exception))
  5291. def testMkimageFilename(self):
  5292. """Test using mkimage to build a binary with a filename"""
  5293. self._SetupSplElf()
  5294. retcode = self._DoTestFile('254_mkimage_filename.dts')
  5295. self.assertEqual(0, retcode)
  5296. fname = tools.get_output_filename('mkimage-test.bin')
  5297. self.assertTrue(os.path.exists(fname))
  5298. def testVpl(self):
  5299. """Test that an image with VPL and its device tree can be created"""
  5300. # ELF file with a '__bss_size' symbol
  5301. self._SetupVplElf()
  5302. data = self._DoReadFile('255_u_boot_vpl.dts')
  5303. self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
  5304. def testVplNoDtb(self):
  5305. """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
  5306. self._SetupVplElf()
  5307. data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
  5308. self.assertEqual(U_BOOT_VPL_NODTB_DATA,
  5309. data[:len(U_BOOT_VPL_NODTB_DATA)])
  5310. def testExpandedVpl(self):
  5311. """Test that an expanded entry type is selected for TPL when needed"""
  5312. self._SetupVplElf()
  5313. entry_args = {
  5314. 'vpl-bss-pad': 'y',
  5315. 'vpl-dtb': 'y',
  5316. }
  5317. self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
  5318. entry_args=entry_args)
  5319. image = control.images['image']
  5320. entries = image.GetEntries()
  5321. self.assertEqual(1, len(entries))
  5322. # We only have u-boot-vpl, which be expanded
  5323. self.assertIn('u-boot-vpl', entries)
  5324. entry = entries['u-boot-vpl']
  5325. self.assertEqual('u-boot-vpl-expanded', entry.etype)
  5326. subent = entry.GetEntries()
  5327. self.assertEqual(3, len(subent))
  5328. self.assertIn('u-boot-vpl-nodtb', subent)
  5329. self.assertIn('u-boot-vpl-bss-pad', subent)
  5330. self.assertIn('u-boot-vpl-dtb', subent)
  5331. def testVplBssPadMissing(self):
  5332. """Test that a missing symbol is detected"""
  5333. self._SetupVplElf('u_boot_ucode_ptr')
  5334. with self.assertRaises(ValueError) as e:
  5335. self._DoReadFile('258_vpl_bss_pad.dts')
  5336. self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
  5337. str(e.exception))
  5338. def testSymlink(self):
  5339. """Test that image files can be symlinked"""
  5340. retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
  5341. self.assertEqual(0, retcode)
  5342. image = control.images['test_image']
  5343. fname = tools.get_output_filename('test_image.bin')
  5344. sname = tools.get_output_filename('symlink_to_test.bin')
  5345. self.assertTrue(os.path.islink(sname))
  5346. self.assertEqual(os.readlink(sname), fname)
  5347. def testSymlinkOverwrite(self):
  5348. """Test that symlinked images can be overwritten"""
  5349. testdir = TestFunctional._MakeInputDir('symlinktest')
  5350. self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
  5351. # build the same image again in the same directory so that existing symlink is present
  5352. self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
  5353. fname = tools.get_output_filename('test_image.bin')
  5354. sname = tools.get_output_filename('symlink_to_test.bin')
  5355. self.assertTrue(os.path.islink(sname))
  5356. self.assertEqual(os.readlink(sname), fname)
  5357. def testSymbolsElf(self):
  5358. """Test binman can assign symbols embedded in an ELF file"""
  5359. if not elf.ELF_TOOLS:
  5360. self.skipTest('Python elftools not available')
  5361. self._SetupTplElf('u_boot_binman_syms')
  5362. self._SetupVplElf('u_boot_binman_syms')
  5363. self._SetupSplElf('u_boot_binman_syms')
  5364. data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
  5365. image_fname = tools.get_output_filename('image.bin')
  5366. image = control.images['image']
  5367. entries = image.GetEntries()
  5368. for entry in entries.values():
  5369. # No symbols in u-boot and it has faked contents anyway
  5370. if entry.name == 'u-boot':
  5371. continue
  5372. edata = data[entry.image_pos:entry.image_pos + entry.size]
  5373. efname = tools.get_output_filename(f'edata-{entry.name}')
  5374. tools.write_file(efname, edata)
  5375. syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
  5376. re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
  5377. for name, sym in syms.items():
  5378. msg = 'test'
  5379. val = elf.GetSymbolValue(sym, edata, msg)
  5380. entry_m = re_name.match(name)
  5381. if entry_m:
  5382. ename, prop = entry_m.group(1), entry_m.group(3)
  5383. entry, entry_name, prop_name = image.LookupEntry(entries,
  5384. name, msg)
  5385. if prop_name == 'offset':
  5386. expect_val = entry.offset
  5387. elif prop_name == 'image_pos':
  5388. expect_val = entry.image_pos
  5389. elif prop_name == 'size':
  5390. expect_val = entry.size
  5391. self.assertEqual(expect_val, val)
  5392. def testSymbolsElfBad(self):
  5393. """Check error when trying to write symbols without the elftools lib"""
  5394. if not elf.ELF_TOOLS:
  5395. self.skipTest('Python elftools not available')
  5396. self._SetupTplElf('u_boot_binman_syms')
  5397. self._SetupVplElf('u_boot_binman_syms')
  5398. self._SetupSplElf('u_boot_binman_syms')
  5399. try:
  5400. elf.ELF_TOOLS = False
  5401. with self.assertRaises(ValueError) as exc:
  5402. self._DoReadFileDtb('260_symbols_elf.dts')
  5403. finally:
  5404. elf.ELF_TOOLS = True
  5405. self.assertIn(
  5406. "Section '/binman': entry '/binman/u-boot-spl-elf': "
  5407. 'Cannot write symbols to an ELF file without Python elftools',
  5408. str(exc.exception))
  5409. def testSectionFilename(self):
  5410. """Check writing of section contents to a file"""
  5411. data = self._DoReadFile('261_section_fname.dts')
  5412. expected = (b'&&' + U_BOOT_DATA + b'&&&' +
  5413. tools.get_bytes(ord('!'), 7) +
  5414. U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
  5415. self.assertEqual(expected, data)
  5416. sect_fname = tools.get_output_filename('outfile.bin')
  5417. self.assertTrue(os.path.exists(sect_fname))
  5418. sect_data = tools.read_file(sect_fname)
  5419. self.assertEqual(U_BOOT_DATA, sect_data)
  5420. def testAbsent(self):
  5421. """Check handling of absent entries"""
  5422. data = self._DoReadFile('262_absent.dts')
  5423. self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
  5424. def testPackTeeOsOptional(self):
  5425. """Test that an image with an optional TEE binary can be created"""
  5426. entry_args = {
  5427. 'tee-os-path': 'tee.elf',
  5428. }
  5429. data = self._DoReadFileDtb('263_tee_os_opt.dts',
  5430. entry_args=entry_args)[0]
  5431. self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
  5432. def checkFitTee(self, dts, tee_fname):
  5433. """Check that a tee-os entry works and returns data
  5434. Args:
  5435. dts (str): Device tree filename to use
  5436. tee_fname (str): filename containing tee-os
  5437. Returns:
  5438. bytes: Image contents
  5439. """
  5440. if not elf.ELF_TOOLS:
  5441. self.skipTest('Python elftools not available')
  5442. entry_args = {
  5443. 'of-list': 'test-fdt1 test-fdt2',
  5444. 'default-dt': 'test-fdt2',
  5445. 'tee-os-path': tee_fname,
  5446. }
  5447. test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
  5448. data = self._DoReadFileDtb(dts, entry_args=entry_args,
  5449. extra_indirs=[test_subdir])[0]
  5450. return data
  5451. def testFitTeeOsOptionalFit(self):
  5452. """Test an image with a FIT with an optional OP-TEE binary"""
  5453. data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
  5454. # There should be only one node, holding the data set up in SetUpClass()
  5455. # for tee.bin
  5456. dtb = fdt.Fdt.FromData(data)
  5457. dtb.Scan()
  5458. node = dtb.GetNode('/images/tee-1')
  5459. self.assertEqual(TEE_ADDR,
  5460. fdt_util.fdt32_to_cpu(node.props['load'].value))
  5461. self.assertEqual(TEE_ADDR,
  5462. fdt_util.fdt32_to_cpu(node.props['entry'].value))
  5463. self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
  5464. with test_util.capture_sys_output() as (stdout, stderr):
  5465. self.checkFitTee('264_tee_os_opt_fit.dts', '')
  5466. err = stderr.getvalue()
  5467. self.assertRegex(
  5468. err,
  5469. "Image '.*' is missing optional external blobs but is still functional: tee-os")
  5470. def testFitTeeOsOptionalFitBad(self):
  5471. """Test an image with a FIT with an optional OP-TEE binary"""
  5472. with self.assertRaises(ValueError) as exc:
  5473. self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
  5474. self.assertIn(
  5475. "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
  5476. str(exc.exception))
  5477. def testFitTeeOsBad(self):
  5478. """Test an OP-TEE binary with wrong formats"""
  5479. self.make_tee_bin('tee.bad1', 123)
  5480. with self.assertRaises(ValueError) as exc:
  5481. self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
  5482. self.assertIn(
  5483. "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
  5484. str(exc.exception))
  5485. self.make_tee_bin('tee.bad2', 0, b'extra data')
  5486. with self.assertRaises(ValueError) as exc:
  5487. self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
  5488. self.assertIn(
  5489. "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
  5490. str(exc.exception))
  5491. def testExtblobOptional(self):
  5492. """Test an image with an external blob that is optional"""
  5493. with test_util.capture_sys_output() as (stdout, stderr):
  5494. data = self._DoReadFile('266_blob_ext_opt.dts')
  5495. self.assertEqual(REFCODE_DATA, data)
  5496. err = stderr.getvalue()
  5497. self.assertRegex(
  5498. err,
  5499. "Image '.*' is missing optional external blobs but is still functional: missing")
  5500. def testSectionInner(self):
  5501. """Test an inner section with a size"""
  5502. data = self._DoReadFile('267_section_inner.dts')
  5503. expected = U_BOOT_DATA + tools.get_bytes(0, 12)
  5504. self.assertEqual(expected, data)
  5505. def testNull(self):
  5506. """Test an image with a null entry"""
  5507. data = self._DoReadFile('268_null.dts')
  5508. self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
  5509. def testOverlap(self):
  5510. """Test an image with a overlapping entry"""
  5511. data = self._DoReadFile('269_overlap.dts')
  5512. self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
  5513. image = control.images['image']
  5514. entries = image.GetEntries()
  5515. self.assertIn('inset', entries)
  5516. inset = entries['inset']
  5517. self.assertEqual(1, inset.offset);
  5518. self.assertEqual(1, inset.image_pos);
  5519. self.assertEqual(2, inset.size);
  5520. def testOverlapNull(self):
  5521. """Test an image with a null overlap"""
  5522. data = self._DoReadFile('270_overlap_null.dts')
  5523. self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
  5524. # Check the FMAP
  5525. fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
  5526. self.assertEqual(4, fhdr.nareas)
  5527. fiter = iter(fentries)
  5528. fentry = next(fiter)
  5529. self.assertEqual(b'SECTION', fentry.name)
  5530. self.assertEqual(0, fentry.offset)
  5531. self.assertEqual(len(U_BOOT_DATA), fentry.size)
  5532. self.assertEqual(0, fentry.flags)
  5533. fentry = next(fiter)
  5534. self.assertEqual(b'U_BOOT', fentry.name)
  5535. self.assertEqual(0, fentry.offset)
  5536. self.assertEqual(len(U_BOOT_DATA), fentry.size)
  5537. self.assertEqual(0, fentry.flags)
  5538. # Make sure that the NULL entry appears in the FMAP
  5539. fentry = next(fiter)
  5540. self.assertEqual(b'NULL', fentry.name)
  5541. self.assertEqual(1, fentry.offset)
  5542. self.assertEqual(2, fentry.size)
  5543. self.assertEqual(0, fentry.flags)
  5544. fentry = next(fiter)
  5545. self.assertEqual(b'FMAP', fentry.name)
  5546. self.assertEqual(len(U_BOOT_DATA), fentry.offset)
  5547. def testOverlapBad(self):
  5548. """Test an image with a bad overlapping entry"""
  5549. with self.assertRaises(ValueError) as exc:
  5550. self._DoReadFile('271_overlap_bad.dts')
  5551. self.assertIn(
  5552. "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
  5553. str(exc.exception))
  5554. def testOverlapNoOffset(self):
  5555. """Test an image with a bad overlapping entry"""
  5556. with self.assertRaises(ValueError) as exc:
  5557. self._DoReadFile('272_overlap_no_size.dts')
  5558. self.assertIn(
  5559. "Node '/binman/inset': 'fill' entry is missing properties: size",
  5560. str(exc.exception))
  5561. def testBlobSymbol(self):
  5562. """Test a blob with symbols read from an ELF file"""
  5563. elf_fname = self.ElfTestFile('blob_syms')
  5564. TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
  5565. TestFunctional._MakeInputFile('blob_syms.bin',
  5566. tools.read_file(self.ElfTestFile('blob_syms.bin')))
  5567. data = self._DoReadFile('273_blob_symbol.dts')
  5568. syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
  5569. addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
  5570. self.assertEqual(syms['_binman_sym_magic'].address, addr)
  5571. self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
  5572. self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
  5573. sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
  5574. expected = sym_values
  5575. self.assertEqual(expected, data[:len(expected)])
  5576. def testOffsetFromElf(self):
  5577. """Test a blob with symbols read from an ELF file"""
  5578. elf_fname = self.ElfTestFile('blob_syms')
  5579. TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
  5580. TestFunctional._MakeInputFile('blob_syms.bin',
  5581. tools.read_file(self.ElfTestFile('blob_syms.bin')))
  5582. data = self._DoReadFile('274_offset_from_elf.dts')
  5583. syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
  5584. base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
  5585. image = control.images['image']
  5586. entries = image.GetEntries()
  5587. self.assertIn('inset', entries)
  5588. inset = entries['inset']
  5589. self.assertEqual(base + 4, inset.offset);
  5590. self.assertEqual(base + 4, inset.image_pos);
  5591. self.assertEqual(4, inset.size);
  5592. self.assertIn('inset2', entries)
  5593. inset = entries['inset2']
  5594. self.assertEqual(base + 8, inset.offset);
  5595. self.assertEqual(base + 8, inset.image_pos);
  5596. self.assertEqual(4, inset.size);
  5597. def testFitAlign(self):
  5598. """Test an image with an FIT with aligned external data"""
  5599. data = self._DoReadFile('275_fit_align.dts')
  5600. self.assertEqual(4096, len(data))
  5601. dtb = fdt.Fdt.FromData(data)
  5602. dtb.Scan()
  5603. props = self._GetPropTree(dtb, ['data-position'])
  5604. expected = {
  5605. 'u-boot:data-position': 1024,
  5606. 'fdt-1:data-position': 2048,
  5607. 'fdt-2:data-position': 3072,
  5608. }
  5609. self.assertEqual(expected, props)
  5610. def testFitFirmwareLoadables(self):
  5611. """Test an image with an FIT that use fit,firmware"""
  5612. if not elf.ELF_TOOLS:
  5613. self.skipTest('Python elftools not available')
  5614. entry_args = {
  5615. 'of-list': 'test-fdt1',
  5616. 'default-dt': 'test-fdt1',
  5617. 'atf-bl31-path': 'bl31.elf',
  5618. 'tee-os-path': 'missing.bin',
  5619. }
  5620. test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
  5621. with test_util.capture_sys_output() as (stdout, stderr):
  5622. data = self._DoReadFileDtb(
  5623. '276_fit_firmware_loadables.dts',
  5624. entry_args=entry_args,
  5625. extra_indirs=[test_subdir])[0]
  5626. dtb = fdt.Fdt.FromData(data)
  5627. dtb.Scan()
  5628. node = dtb.GetNode('/configurations/conf-uboot-1')
  5629. self.assertEqual('u-boot', node.props['firmware'].value)
  5630. self.assertEqual(['atf-1', 'atf-2'],
  5631. fdt_util.GetStringList(node, 'loadables'))
  5632. node = dtb.GetNode('/configurations/conf-atf-1')
  5633. self.assertEqual('atf-1', node.props['firmware'].value)
  5634. self.assertEqual(['u-boot', 'atf-2'],
  5635. fdt_util.GetStringList(node, 'loadables'))
  5636. node = dtb.GetNode('/configurations/conf-missing-uboot-1')
  5637. self.assertEqual('u-boot', node.props['firmware'].value)
  5638. self.assertEqual(['atf-1', 'atf-2'],
  5639. fdt_util.GetStringList(node, 'loadables'))
  5640. node = dtb.GetNode('/configurations/conf-missing-atf-1')
  5641. self.assertEqual('atf-1', node.props['firmware'].value)
  5642. self.assertEqual(['u-boot', 'atf-2'],
  5643. fdt_util.GetStringList(node, 'loadables'))
  5644. node = dtb.GetNode('/configurations/conf-missing-tee-1')
  5645. self.assertEqual('atf-1', node.props['firmware'].value)
  5646. self.assertEqual(['u-boot', 'atf-2'],
  5647. fdt_util.GetStringList(node, 'loadables'))
  5648. def testTooldir(self):
  5649. """Test that we can specify the tooldir"""
  5650. with test_util.capture_sys_output() as (stdout, stderr):
  5651. self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
  5652. 'tool', '-l'))
  5653. self.assertEqual('fred', bintool.Bintool.tooldir)
  5654. # Check that the toolpath is updated correctly
  5655. self.assertEqual(['fred'], tools.tool_search_paths)
  5656. # Try with a few toolpaths; the tooldir should be at the end
  5657. with test_util.capture_sys_output() as (stdout, stderr):
  5658. self.assertEqual(0, self._DoBinman(
  5659. '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
  5660. 'tool', '-l'))
  5661. self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
  5662. def testReplaceSectionEntry(self):
  5663. """Test replacing an entry in a section"""
  5664. expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
  5665. entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
  5666. expect_data, dts='241_replace_section_simple.dts')
  5667. self.assertEqual(expect_data, entry_data)
  5668. entries = image.GetEntries()
  5669. self.assertIn('section', entries)
  5670. section = entries['section']
  5671. sect_entries = section.GetEntries()
  5672. self.assertIn('blob', sect_entries)
  5673. entry = sect_entries['blob']
  5674. self.assertEqual(len(expect_data), entry.size)
  5675. fname = tools.get_output_filename('image-updated.bin')
  5676. data = tools.read_file(fname)
  5677. new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
  5678. self.assertEqual(expect_data, new_blob_data)
  5679. self.assertEqual(U_BOOT_DATA,
  5680. data[entry.image_pos + len(expect_data):]
  5681. [:len(U_BOOT_DATA)])
  5682. def testReplaceSectionDeep(self):
  5683. """Test replacing an entry in two levels of sections"""
  5684. expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
  5685. entry_data, expected_fdtmap, image = self._RunReplaceCmd(
  5686. 'section/section/blob', expect_data,
  5687. dts='278_replace_section_deep.dts')
  5688. self.assertEqual(expect_data, entry_data)
  5689. entries = image.GetEntries()
  5690. self.assertIn('section', entries)
  5691. section = entries['section']
  5692. subentries = section.GetEntries()
  5693. self.assertIn('section', subentries)
  5694. section = subentries['section']
  5695. sect_entries = section.GetEntries()
  5696. self.assertIn('blob', sect_entries)
  5697. entry = sect_entries['blob']
  5698. self.assertEqual(len(expect_data), entry.size)
  5699. fname = tools.get_output_filename('image-updated.bin')
  5700. data = tools.read_file(fname)
  5701. new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
  5702. self.assertEqual(expect_data, new_blob_data)
  5703. self.assertEqual(U_BOOT_DATA,
  5704. data[entry.image_pos + len(expect_data):]
  5705. [:len(U_BOOT_DATA)])
  5706. def testReplaceFitSibling(self):
  5707. """Test an image with a FIT inside where we replace its sibling"""
  5708. self._SetupSplElf()
  5709. fname = TestFunctional._MakeInputFile('once', b'available once')
  5710. self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
  5711. os.remove(fname)
  5712. try:
  5713. tmpdir, updated_fname = self._SetupImageInTmpdir()
  5714. fname = os.path.join(tmpdir, 'update-blob')
  5715. expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
  5716. tools.write_file(fname, expected)
  5717. self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
  5718. data = tools.read_file(updated_fname)
  5719. start = len(U_BOOT_DTB_DATA)
  5720. self.assertEqual(expected, data[start:start + len(expected)])
  5721. map_fname = os.path.join(tmpdir, 'image-updated.map')
  5722. self.assertFalse(os.path.exists(map_fname))
  5723. finally:
  5724. shutil.rmtree(tmpdir)
  5725. def testX509Cert(self):
  5726. """Test creating an X509 certificate"""
  5727. keyfile = self.TestFile('key.key')
  5728. entry_args = {
  5729. 'keyfile': keyfile,
  5730. }
  5731. data = self._DoReadFileDtb('279_x509_cert.dts',
  5732. entry_args=entry_args)[0]
  5733. cert = data[:-4]
  5734. self.assertEqual(U_BOOT_DATA, data[-4:])
  5735. # TODO: verify the signature
  5736. def testX509CertMissing(self):
  5737. """Test that binman still produces an image if openssl is missing"""
  5738. keyfile = self.TestFile('key.key')
  5739. entry_args = {
  5740. 'keyfile': 'keyfile',
  5741. }
  5742. with test_util.capture_sys_output() as (_, stderr):
  5743. self._DoTestFile('279_x509_cert.dts',
  5744. force_missing_bintools='openssl',
  5745. entry_args=entry_args)
  5746. err = stderr.getvalue()
  5747. self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
  5748. def testPackRockchipTpl(self):
  5749. """Test that an image with a Rockchip TPL binary can be created"""
  5750. data = self._DoReadFile('291_rockchip_tpl.dts')
  5751. self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
  5752. def testMkimageMissingBlobMultiple(self):
  5753. """Test missing blob with mkimage entry and multiple-data-files"""
  5754. with test_util.capture_sys_output() as (stdout, stderr):
  5755. self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
  5756. err = stderr.getvalue()
  5757. self.assertIn("is missing external blobs and is non-functional", err)
  5758. with self.assertRaises(ValueError) as e:
  5759. self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
  5760. self.assertIn("not found in input path", str(e.exception))
  5761. def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
  5762. """Prepare sign environment
  5763. Create private and public keys, add pubkey into dtb.
  5764. Returns:
  5765. Tuple:
  5766. FIT container
  5767. Image name
  5768. Private key
  5769. DTB
  5770. """
  5771. self._SetupSplElf()
  5772. data = self._DoReadFileRealDtb(dts)
  5773. updated_fname = tools.get_output_filename('image-updated.bin')
  5774. tools.write_file(updated_fname, data)
  5775. dtb = tools.get_output_filename('source.dtb')
  5776. private_key = tools.get_output_filename('test_key.key')
  5777. public_key = tools.get_output_filename('test_key.crt')
  5778. fit = tools.get_output_filename('fit.fit')
  5779. key_dir = tools.get_output_dir()
  5780. tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
  5781. '-sha256', '-new', '-nodes', '-x509', '-keyout',
  5782. private_key, '-out', public_key)
  5783. tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
  5784. '-n', 'test_key', '-r', 'conf', dtb)
  5785. return fit, updated_fname, private_key, dtb
  5786. def testSignSimple(self):
  5787. """Test that a FIT container can be signed in image"""
  5788. is_signed = False
  5789. fit, fname, private_key, dtb = self._PrepareSignEnv()
  5790. # do sign with private key
  5791. control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
  5792. ['fit'])
  5793. is_signed = self._CheckSign(fit, dtb)
  5794. self.assertEqual(is_signed, True)
  5795. def testSignExactFIT(self):
  5796. """Test that a FIT container can be signed and replaced in image"""
  5797. is_signed = False
  5798. fit, fname, private_key, dtb = self._PrepareSignEnv()
  5799. # Make sure we propagate the toolpath, since mkimage may not be on PATH
  5800. args = []
  5801. if self.toolpath:
  5802. for path in self.toolpath:
  5803. args += ['--toolpath', path]
  5804. # do sign with private key
  5805. self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
  5806. 'sha256,rsa4096', '-f', fit, 'fit')
  5807. is_signed = self._CheckSign(fit, dtb)
  5808. self.assertEqual(is_signed, True)
  5809. def testSignNonFit(self):
  5810. """Test a non-FIT entry cannot be signed"""
  5811. is_signed = False
  5812. fit, fname, private_key, _ = self._PrepareSignEnv(
  5813. '281_sign_non_fit.dts')
  5814. # do sign with private key
  5815. with self.assertRaises(ValueError) as e:
  5816. self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
  5817. 'sha256,rsa4096', '-f', fit, 'u-boot')
  5818. self.assertIn(
  5819. "Node '/u-boot': Updating signatures is not supported with this entry type",
  5820. str(e.exception))
  5821. def testSignMissingMkimage(self):
  5822. """Test that FIT signing handles a missing mkimage tool"""
  5823. fit, fname, private_key, _ = self._PrepareSignEnv()
  5824. # try to sign with a missing mkimage tool
  5825. bintool.Bintool.set_missing_list(['mkimage'])
  5826. with self.assertRaises(ValueError) as e:
  5827. control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
  5828. ['fit'])
  5829. self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
  5830. def testSymbolNoWrite(self):
  5831. """Test disabling of symbol writing"""
  5832. self._SetupSplElf()
  5833. self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
  5834. no_write_symbols=True)
  5835. def testSymbolNoWriteExpanded(self):
  5836. """Test disabling of symbol writing in expanded entries"""
  5837. entry_args = {
  5838. 'spl-dtb': '1',
  5839. }
  5840. self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
  5841. U_BOOT_SPL_DTB_DATA, 0x38,
  5842. entry_args=entry_args, use_expanded=True,
  5843. no_write_symbols=True)
  5844. def testMkimageSpecial(self):
  5845. """Test mkimage ignores special hash-1 node"""
  5846. data = self._DoReadFile('283_mkimage_special.dts')
  5847. # Just check that the data appears in the file somewhere
  5848. self.assertIn(U_BOOT_DATA, data)
  5849. def testFitFdtList(self):
  5850. """Test an image with an FIT with the fit,fdt-list-val option"""
  5851. entry_args = {
  5852. 'default-dt': 'test-fdt2',
  5853. }
  5854. data = self._DoReadFileDtb(
  5855. '284_fit_fdt_list.dts',
  5856. entry_args=entry_args,
  5857. extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
  5858. self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
  5859. fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
  5860. def testSplEmptyBss(self):
  5861. """Test an expanded SPL with a zero-size BSS"""
  5862. # ELF file with a '__bss_size' symbol
  5863. self._SetupSplElf(src_fname='bss_data_zero')
  5864. entry_args = {
  5865. 'spl-bss-pad': 'y',
  5866. 'spl-dtb': 'y',
  5867. }
  5868. data = self._DoReadFileDtb('285_spl_expand.dts',
  5869. use_expanded=True, entry_args=entry_args)[0]
  5870. def testTemplate(self):
  5871. """Test using a template"""
  5872. TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
  5873. data = self._DoReadFile('286_template.dts')
  5874. first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
  5875. second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
  5876. self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
  5877. dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
  5878. self.assertTrue(os.path.exists(dtb_fname1))
  5879. dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
  5880. dtb.Scan()
  5881. node1 = dtb.GetNode('/binman/template')
  5882. self.assertTrue(node1)
  5883. vga = dtb.GetNode('/binman/first/intel-vga')
  5884. self.assertTrue(vga)
  5885. dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
  5886. self.assertTrue(os.path.exists(dtb_fname2))
  5887. dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
  5888. dtb2.Scan()
  5889. node2 = dtb2.GetNode('/binman/template')
  5890. self.assertFalse(node2)
  5891. def testTemplateBlobMulti(self):
  5892. """Test using a template with 'multiple-images' enabled"""
  5893. TestFunctional._MakeInputFile('my-blob.bin', b'blob')
  5894. TestFunctional._MakeInputFile('my-blob2.bin', b'other')
  5895. retcode = self._DoTestFile('287_template_multi.dts')
  5896. self.assertEqual(0, retcode)
  5897. image = control.images['image']
  5898. image_fname = tools.get_output_filename('my-image.bin')
  5899. data = tools.read_file(image_fname)
  5900. self.assertEqual(b'blob@@@@other', data)
  5901. def testTemplateFit(self):
  5902. """Test using a template in a FIT"""
  5903. fit_data = self._DoReadFile('288_template_fit.dts')
  5904. fname = os.path.join(self._indir, 'fit_data.fit')
  5905. tools.write_file(fname, fit_data)
  5906. out = tools.run('dumpimage', '-l', fname)
  5907. def testTemplateSection(self):
  5908. """Test using a template in a section (not at top level)"""
  5909. TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
  5910. data = self._DoReadFile('289_template_section.dts')
  5911. first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
  5912. second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
  5913. self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
  5914. def testMkimageSymbols(self):
  5915. """Test using mkimage to build an image with symbols in it"""
  5916. self._SetupSplElf('u_boot_binman_syms')
  5917. data = self._DoReadFile('290_mkimage_sym.dts')
  5918. image = control.images['image']
  5919. entries = image.GetEntries()
  5920. self.assertIn('u-boot', entries)
  5921. u_boot = entries['u-boot']
  5922. mkim = entries['mkimage']
  5923. mkim_entries = mkim.GetEntries()
  5924. self.assertIn('u-boot-spl', mkim_entries)
  5925. spl = mkim_entries['u-boot-spl']
  5926. self.assertIn('u-boot-spl2', mkim_entries)
  5927. spl2 = mkim_entries['u-boot-spl2']
  5928. # skip the mkimage header and the area sizes
  5929. mk_data = data[mkim.offset + 0x40:]
  5930. size, term = struct.unpack('>LL', mk_data[:8])
  5931. # There should be only one image, so check that the zero terminator is
  5932. # present
  5933. self.assertEqual(0, term)
  5934. content = mk_data[8:8 + size]
  5935. # The image should contain the symbols from u_boot_binman_syms.c
  5936. # Note that image_pos is adjusted by the base address of the image,
  5937. # which is 0x10 in our test image
  5938. spl_data = content[:0x18]
  5939. content = content[0x1b:]
  5940. # After the header is a table of offsets for each image. There should
  5941. # only be one image, then a 0 terminator, so figure out the real start
  5942. # of the image data
  5943. base = 0x40 + 8
  5944. # Check symbols in both u-boot-spl and u-boot-spl2
  5945. for i in range(2):
  5946. vals = struct.unpack('<LLQLL', spl_data)
  5947. # The image should contain the symbols from u_boot_binman_syms.c
  5948. # Note that image_pos is adjusted by the base address of the image,
  5949. # which is 0x10 in our 'u_boot_binman_syms' test image
  5950. self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
  5951. self.assertEqual(base, vals[1])
  5952. self.assertEqual(spl2.offset, vals[2])
  5953. # figure out the internal positions of its components
  5954. self.assertEqual(0x10 + u_boot.image_pos, vals[3])
  5955. # Check that spl and spl2 are actually at the indicated positions
  5956. self.assertEqual(
  5957. elf.BINMAN_SYM_MAGIC_VALUE,
  5958. struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
  5959. self.assertEqual(
  5960. elf.BINMAN_SYM_MAGIC_VALUE,
  5961. struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
  5962. self.assertEqual(len(U_BOOT_DATA), vals[4])
  5963. # Move to next
  5964. spl_data = content[:0x18]
  5965. def testTemplatePhandle(self):
  5966. """Test using a template in a node containing a phandle"""
  5967. entry_args = {
  5968. 'atf-bl31-path': 'bl31.elf',
  5969. }
  5970. data = self._DoReadFileDtb('309_template_phandle.dts',
  5971. entry_args=entry_args)
  5972. fname = tools.get_output_filename('image.bin')
  5973. out = tools.run('dumpimage', '-l', fname)
  5974. # We should see the FIT description and one for each of the two images
  5975. lines = out.splitlines()
  5976. descs = [line.split()[-1] for line in lines if 'escription' in line]
  5977. self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
  5978. def testTemplatePhandleDup(self):
  5979. """Test using a template in a node containing a phandle"""
  5980. entry_args = {
  5981. 'atf-bl31-path': 'bl31.elf',
  5982. }
  5983. with self.assertRaises(ValueError) as e:
  5984. self._DoReadFileDtb('310_template_phandle_dup.dts',
  5985. entry_args=entry_args)
  5986. self.assertIn(
  5987. 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
  5988. str(e.exception))
  5989. def testTIBoardConfig(self):
  5990. """Test that a schema validated board config file can be generated"""
  5991. data = self._DoReadFile('293_ti_board_cfg.dts')
  5992. self.assertEqual(TI_BOARD_CONFIG_DATA, data)
  5993. def testTIBoardConfigCombined(self):
  5994. """Test that a schema validated combined board config file can be generated"""
  5995. data = self._DoReadFile('294_ti_board_cfg_combined.dts')
  5996. configlen_noheader = TI_BOARD_CONFIG_DATA * 4
  5997. self.assertGreater(data, configlen_noheader)
  5998. def testTIBoardConfigNoDataType(self):
  5999. """Test that error is thrown when data type is not supported"""
  6000. with self.assertRaises(ValueError) as e:
  6001. data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
  6002. self.assertIn("Schema validation error", str(e.exception))
  6003. def testPackTiSecure(self):
  6004. """Test that an image with a TI secured binary can be created"""
  6005. keyfile = self.TestFile('key.key')
  6006. entry_args = {
  6007. 'keyfile': keyfile,
  6008. }
  6009. data = self._DoReadFileDtb('296_ti_secure.dts',
  6010. entry_args=entry_args)[0]
  6011. self.assertGreater(len(data), len(TI_UNSECURE_DATA))
  6012. def testPackTiSecureMissingTool(self):
  6013. """Test that an image with a TI secured binary (non-functional) can be created
  6014. when openssl is missing"""
  6015. keyfile = self.TestFile('key.key')
  6016. entry_args = {
  6017. 'keyfile': keyfile,
  6018. }
  6019. with test_util.capture_sys_output() as (_, stderr):
  6020. self._DoTestFile('296_ti_secure.dts',
  6021. force_missing_bintools='openssl',
  6022. entry_args=entry_args)
  6023. err = stderr.getvalue()
  6024. self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
  6025. def testPackTiSecureROM(self):
  6026. """Test that a ROM image with a TI secured binary can be created"""
  6027. keyfile = self.TestFile('key.key')
  6028. entry_args = {
  6029. 'keyfile': keyfile,
  6030. }
  6031. data = self._DoReadFileDtb('297_ti_secure_rom.dts',
  6032. entry_args=entry_args)[0]
  6033. data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
  6034. entry_args=entry_args)[0]
  6035. data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
  6036. entry_args=entry_args)[0]
  6037. self.assertGreater(len(data), len(TI_UNSECURE_DATA))
  6038. self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
  6039. self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
  6040. def testPackTiSecureROMCombined(self):
  6041. """Test that a ROM image with a TI secured binary can be created"""
  6042. keyfile = self.TestFile('key.key')
  6043. entry_args = {
  6044. 'keyfile': keyfile,
  6045. }
  6046. data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
  6047. entry_args=entry_args)[0]
  6048. self.assertGreater(len(data), len(TI_UNSECURE_DATA))
  6049. def testEncryptedNoAlgo(self):
  6050. """Test encrypted node with missing required properties"""
  6051. with self.assertRaises(ValueError) as e:
  6052. self._DoReadFileDtb('301_encrypted_no_algo.dts')
  6053. self.assertIn(
  6054. "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
  6055. str(e.exception))
  6056. def testEncryptedInvalidIvfile(self):
  6057. """Test encrypted node with invalid iv file"""
  6058. with self.assertRaises(ValueError) as e:
  6059. self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
  6060. self.assertIn("Filename 'invalid-iv-file' not found in input path",
  6061. str(e.exception))
  6062. def testEncryptedMissingKey(self):
  6063. """Test encrypted node with missing key properties"""
  6064. with self.assertRaises(ValueError) as e:
  6065. self._DoReadFileDtb('303_encrypted_missing_key.dts')
  6066. self.assertIn(
  6067. "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
  6068. str(e.exception))
  6069. def testEncryptedKeySource(self):
  6070. """Test encrypted node with key-source property"""
  6071. data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
  6072. dtb = fdt.Fdt.FromData(data)
  6073. dtb.Scan()
  6074. node = dtb.GetNode('/images/u-boot/cipher')
  6075. self.assertEqual('algo-name', node.props['algo'].value)
  6076. self.assertEqual('key-source-value', node.props['key-source'].value)
  6077. self.assertEqual(ENCRYPTED_IV_DATA,
  6078. tools.to_bytes(''.join(node.props['iv'].value)))
  6079. self.assertNotIn('key', node.props)
  6080. def testEncryptedKeyFile(self):
  6081. """Test encrypted node with key-filename property"""
  6082. data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
  6083. dtb = fdt.Fdt.FromData(data)
  6084. dtb.Scan()
  6085. node = dtb.GetNode('/images/u-boot/cipher')
  6086. self.assertEqual('algo-name', node.props['algo'].value)
  6087. self.assertEqual(ENCRYPTED_IV_DATA,
  6088. tools.to_bytes(''.join(node.props['iv'].value)))
  6089. self.assertEqual(ENCRYPTED_KEY_DATA,
  6090. tools.to_bytes(''.join(node.props['key'].value)))
  6091. self.assertNotIn('key-source', node.props)
  6092. def testSplPubkeyDtb(self):
  6093. """Test u_boot_spl_pubkey_dtb etype"""
  6094. data = tools.read_file(self.TestFile("key.pem"))
  6095. self._MakeInputFile("key.crt", data)
  6096. self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
  6097. image = control.images['image']
  6098. entries = image.GetEntries()
  6099. dtb_entry = entries['u-boot-spl-pubkey-dtb']
  6100. dtb_data = dtb_entry.GetData()
  6101. dtb = fdt.Fdt.FromData(dtb_data)
  6102. dtb.Scan()
  6103. signature_node = dtb.GetNode('/signature')
  6104. self.assertIsNotNone(signature_node)
  6105. key_node = signature_node.FindNode("key-key")
  6106. self.assertIsNotNone(key_node)
  6107. self.assertEqual(fdt_util.GetString(key_node, "required"),
  6108. "conf")
  6109. self.assertEqual(fdt_util.GetString(key_node, "algo"),
  6110. "sha384,rsa4096")
  6111. self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
  6112. "key")
  6113. def testXilinxBootgenSigning(self):
  6114. """Test xilinx-bootgen etype"""
  6115. bootgen = bintool.Bintool.create('bootgen')
  6116. self._CheckBintool(bootgen)
  6117. data = tools.read_file(self.TestFile("key.key"))
  6118. self._MakeInputFile("psk.pem", data)
  6119. self._MakeInputFile("ssk.pem", data)
  6120. self._SetupPmuFwlElf()
  6121. self._SetupSplElf()
  6122. self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
  6123. image_fname = tools.get_output_filename('image.bin')
  6124. # Read partition header table and check if authentication is enabled
  6125. bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
  6126. "-read", image_fname, "pht").splitlines()
  6127. attributes = {"authentication": None,
  6128. "core": None,
  6129. "encryption": None}
  6130. for l in bootgen_out:
  6131. for a in attributes.keys():
  6132. if a in l:
  6133. m = re.match(fr".*{a} \[([^]]+)\]", l)
  6134. attributes[a] = m.group(1)
  6135. self.assertTrue(attributes['authentication'] == "rsa")
  6136. self.assertTrue(attributes['core'] == "a53-0")
  6137. self.assertTrue(attributes['encryption'] == "no")
  6138. def testXilinxBootgenSigningEncryption(self):
  6139. """Test xilinx-bootgen etype"""
  6140. bootgen = bintool.Bintool.create('bootgen')
  6141. self._CheckBintool(bootgen)
  6142. data = tools.read_file(self.TestFile("key.key"))
  6143. self._MakeInputFile("psk.pem", data)
  6144. self._MakeInputFile("ssk.pem", data)
  6145. self._SetupPmuFwlElf()
  6146. self._SetupSplElf()
  6147. self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
  6148. image_fname = tools.get_output_filename('image.bin')
  6149. # Read boot header in order to verify encryption source and
  6150. # encryption parameter
  6151. bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
  6152. "-read", image_fname, "bh").splitlines()
  6153. attributes = {"auth_only":
  6154. {"re": r".*auth_only \[([^]]+)\]", "value": None},
  6155. "encryption_keystore":
  6156. {"re": r" *encryption_keystore \(0x28\) : (.*)",
  6157. "value": None},
  6158. }
  6159. for l in bootgen_out:
  6160. for a in attributes.keys():
  6161. if a in l:
  6162. m = re.match(attributes[a]['re'], l)
  6163. attributes[a] = m.group(1)
  6164. # Check if fsbl-attribute is set correctly
  6165. self.assertTrue(attributes['auth_only'] == "true")
  6166. # Check if key is stored in efuse
  6167. self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
  6168. def testXilinxBootgenMissing(self):
  6169. """Test that binman still produces an image if bootgen is missing"""
  6170. data = tools.read_file(self.TestFile("key.key"))
  6171. self._MakeInputFile("psk.pem", data)
  6172. self._MakeInputFile("ssk.pem", data)
  6173. self._SetupPmuFwlElf()
  6174. self._SetupSplElf()
  6175. with test_util.capture_sys_output() as (_, stderr):
  6176. self._DoTestFile('307_xilinx_bootgen_sign.dts',
  6177. force_missing_bintools='bootgen')
  6178. err = stderr.getvalue()
  6179. self.assertRegex(err,
  6180. "Image 'image'.*missing bintools.*: bootgen")
  6181. if __name__ == "__main__":
  6182. unittest.main()