MBRsave
di
pubblicato il 01-08-2011 alle 03:05 (3859 Visite)
A volte eventi totalmente indipendenti convergono alle medesime coordinate spaziotemporali con un tempismo a dir poco sorprendente, tanto che non si può fare a meno di pensare alla teoria della sincronicità di Jung e Pauli (la quale peraltro è tornata con forza alla ribalta grazie alle recentissime teorie sul quantum brain).
Capita così che, mentre nell'altra bottega si affaccia nientepopodimeno che Giorgio Ober in persona (un punto di riferimento a livello nazionale per l'Assembly e dintorni), qualche giorno dopo dal fondo dello scatolone di uno strumento di misura emerge un misterioso floppy da 5"¼ privo di etichetta.
Dopo una rapida analisi, il floppy rivelasi essere formattato MS-DOS e contiene tra l'altro una serie di file sorgenti in Assembly creati tra il 1985 e il 1988 su varie macchine 286 e 386 IBM, Olivetti e Compaq.
Tra i vari lavori, salta agli occhi in particolare un file, MBRsave.com: un tool nato in pochi minuti per consentire - lo dice il nome ! - di salvare su file il Master Boot Record degli hard disk installati su una data macchina.
Naturalmente, nell'epoca di cui si discute, gli olandesi autori di questa suite probabilmente indossavano ancora il grembiulino, ammesso che fossero già nati...
Una funzionalità siffatta era offerta unicamente dalle prime versioni di PCTools e Norton Utilities, era disponibile con limitazioni entro il debug.com oppure - ovviamente - era implementata da software sviluppato inhouse come questo.
Sebbene l'utilità pratica di questo tool sia oggi pressoché nulla per un PC mainstream, e altrettanto nulla la complessità del codice, le coincidenze di cui sopra mi invogliano a pubblicarne il sorgente in versione semplificata e ri-commentata: è pur sempre un'ottima scusa per rispolverare saperi esoterici che oggi rischiano di essere totalmente dimenticati dai giovani, e per respirare ancora una volta l'atmosfera di ingegnosa e costruttiva esplorazione, quel sano spirito pionieristico che ha accompagnato gli esordi della "rivoluzione informatica" vissuta appieno sia dalla mia generazione che da quella del buon Giorgio Ober.
Inoltre, come ad esempio già nel caso delle LUT, trovo doveroso venire incontro alle numerose richieste ricevute dagli studenti più giovani, che mi invitano a trattare ogni tanto temi elementari, anche se forse meno interessanti dal punto di vista teorico o applicativo rispetto alla media dei miei interventi.
Cosa faccia l'applicativo in questione è presto detto: tramite una serie di banali chiamate alle API del DOS, e in particolare alla funzione non documentata (da Microsoft) INT25h, va a leggere il primo settore fisico della traccia zero, ossia i primi 512 bytes in assoluto di ciascun disco rigido riconosciuto dal BIOS, e li salva ciascuno in un file allocato in un path prefissato. Il tutto con molto meno di 100 byte di codice binario, una quantità insufficiente perfino a memorizzare una delle icone dei moderni pachidermici applicativi.
Meditate, gente, meditate.
Naturalmente non mancano trucchi del mestiere, che all'epoca tracciavano definitivamente la distanza tra Veri Programmatori e non: in primo luogo, il numero di HD presenti è determinato sbrigativamente con la lettura del byte di configurazione CMOS all'offset 12h, che corrisponde direttamente alle impostazioni di setup del BIOS. Si dà per scontato che almeno un hard disk sia connesso alla macchina: il che, nel contesto applicativo in cui è nato e stato utilizzato il tool, era sempre vero.
Si noti che un tale metodo, una dozzina di anni dopo, è stato reso meno affidabile solo dal riconoscimento automatico introdotto in quasi tutti i BIOS, che non sempre garantiva l'aggiornamento del byte corrispondente.
Tutto ciò implica che, se desiderate lavorare con questo sorgente su una piattaforma embedded tipo SBC 486 o PC-104, dovrete fare meno assunzioni favorevoli sull'environment fisico, e studiare un po'...
Un metodo più "moderno" e portabile per l'enumerazione dei drive fisici su macchine di classe pre-Pentium, se proprio vi pungesse vaghezza di saperlo, consiste nell'inviare direttamente comandi al port di I/O del controller HDD, sfruttando la capacità di autodiagnosi del controller stesso e la presenza di un apposito port a ciò dedicato. Non approfondirò comunque questi aspetti, che sono ampissimamente acclarati nella nanobibliografia allegata.
Mi preme invece rimarcare che questo apparentemente innocente applicativo di poche linee sfrutta bassamente tecniche di self-morphing per cambiare il suo proprio codice a runtime, e questo - decisamente - è il bello dell'Assembly...
PAGE, 132 TITLE MBRSAVE CODE_SEG SEGMENT ASSUME CS:CODE_SEG, DS:CODE_SEG, ES:CODE_SEG ORG 100h MBRSAVE PROC FAR ;*************************************** ;** Stampa del banner introduttivo: ** ;** INT21h, AH = 09h ** ;*************************************** MOV DX, OFFSET Banner MOV AH, 09h INT 21h ;*************************************** ;** Si verifica il numero di HDD ** ;** connessi, tramite le impostazioni ** ;** del BIOS riportate alla locazione ** ;** 12h dei CMOS (port 70h/71h). ** ;** Metodo sbrigativo ma efficace. ** ;*************************************** ;** Il registro SI contiene il numero ** ;** di unita'. ** ;*************************************** MOV SI, 01h MOV AL, 12h OUT 70h, AL IN AL, 71h TEST AL, 00001111b JZ Next INC SI Next: MOV Int25Seg, CS ;*************************************** ;** Si legge il settore 0 tramite una ** ;** chiamata a int25h, usando il ** ;** nuovo formato per il parm pack ** ;*************************************** Read_MBR: MOV CX, 0FFFFh MOV BX, OFFSET Int25Packet Which_drive: MOV AL, 02h INT 25h POP DX MOV DX, OFFSET Read_error JC Errore ;*************************************** ;** Mostra il nome del file prima ** ;** di procedere al salvataggio. ** ;*************************************** MOV AH, 09h MOV DX, OFFSET FileName INT 21h ;*************************************** ;** Si crea il file con troncamento ** ;** (OVERWRITE) se gia' esistente. ** ;*************************************** MOV AH, 3Ch XOR CL, CL INT 21h MOV DX, OFFSET Open_error JC Errore ;*************************************** ;** Si trasferisce l'intero buffer ** ;** nel file appena creato. ** ;*************************************** MOV BX, AX MOV AH, 40h MOV CX, BufSize MOV DX, OFFSET Buffer INT 21h MOV DX, OFFSET Open_error JC Errore ;*************************************** ;** Chiusura del file e report esito ** ;*************************************** MOV AH, 3Eh INT 21h MOV DX, OFFSET OK_Done Errore: MOV AH, 09h INT 21h JC Fine ;*************************************** ;** Se il secondo HDD risulta ** ;** presente, si itera dopo avere ** ;** modificato in-place un paio di ** ;** locazioni importanti: il numero ** ;** BIOS del drive prima della int25h ** ;** e il nome convenzionale del file. ** ;** ** ;** Questo e' il bello dell'assembly! ** ;*************************************** INC BYTE PTR FileName +7 INC BYTE PTR Which_drive +1 DEC SI JNZ Read_MBR Fine: INT 20h MBRSAVE ENDP ;*************************************** ;*************************************** BufSize EQU 200h Int25Packet DD 0 Int25SecCount DW 1 Int25Offset DW OFFSET Buffer Int25Seg DW 0 Banner DB "#********************************#", 0Dh, 0Ah DB "## MBR Saver rel. 1.0 ##", 0Dh, 0Ah DB "## ~-***[M.A.W. 1968]***-~ ##", 0Dh, 0Ah DB "##******************************##", 0Dh, 0Ah DB "## Salva i MBR di tutti gli HD ##", 0Dh, 0Ah DB "## riconosciuti dal BIOS. ##", 0Dh, 0Ah DB "#********************************#", 0Dh, 0Ah, 0Dh, 0Ah, '$' FileName DB "C:\MBR_C.IMG", 0, '$' OK_done DB "-> immagine MBR salvata correttamente.", 0Dh, 0Ah, '$' Read_error DB "## Errore durante la lettura del MBR.", 0Dh, 0Ah, '$' Open_error DB "## Errore durante la creazione del file.", 0Dh, 0Ah, '$' Buffer DB BufSize DUP(?) CODE_SEG ENDS END MBRSAVEHo commentato il codice ad usum delphini, rispettando il vincolo delle 40 colonne come nel sorgente originale. All'epoca valeva comunque il principio "Real programmers don't use comments: their code is obvious enough".
Nota filologica: il sorgente originale era stato sbrigativamente messo assieme qualche anno prima, presumibilmente nel 1985 (ma è datato 01/01/80), ed effettuava il salvataggio su floppy disk - è stato sufficiente variare il path del file di output. Risulta parzialmente modificato in data 3 marzo 1988 per sfruttare/sperimentare la nuova struttura del Parameter Pack di INT25h supportata dal grandioso Compaq DOS 3.31 (e ivi documentata: su carta, s'intende). Una terza versione "portable"e soprattutto well-behaved faceva uso dell'allocazione dinamica del buffer a runtime, per risparmiare 512 bytes di footprint su disco per il file .com (in realtà il medesimo risultato si può ottenere gratuitamente, con un banale trucco, sfruttando il fatto implicito che il loader DOS riserva tutta la memoria disponibile all'applicazione appena caricata).
A proposito di carta, all'epoca - oltre ad innumerevoli nottate di sperimentazione - per imparare tutte queste belle cosette e molte altre, ho studiato, tra i tanti:
- Manuali Compaq DOS 3.31
- Tischer & Jennrich, "PC Intern", Abacus
- Frank van Gilluwe, "The Undocumented PC", AWL
- Michael Podanoffsky, "Dissecting DOS", AWL
- Schulman et aliis, "Undocumented DOS", AWL
- Geoff Chappell, "DOS Internals", AWL