Visualizza il feed RSS

Titolo provvisorio...

MBRsave

Valutazione: 3 voti, con una media del 4.67.
di pubblicato il 01-08-2011 alle 03:05 (3359 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...

codice:
    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     MBRSAVE
Ho 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

aggiornamento da 13-04-2012 a 17:48 di M.A.W. 1968

Categorie
Programmazione

Commenti