MASSIMO UBERTINI MS-DOS WWW.UBERTINI.IT MODULO 1 MS-DOS MS-DOS Processi TSR Memoria File system I/O Comandi MS-DOS um 1 di 138 MS-DOS (MICROSOFT DISK OPERATING SYSTEM) Introduzione MS-DOS gira solo su processori INTEL iAPx86, poiché di questi ne esistono cinquanta milioni, senza dubbio MS-DOS è il SO più usato di tutti i tempi. Il primo PC fu Altair 8800, prodotto nel 1975, di MITS (Micro Instrumentation and Telemetry Systems) di Albuquerque nel New Mexico di Ed Roberts, ex ingegnere dell’aviazione militare USA, con CPU INTEL 8080, aveva 256 KB di RAM. Il primo micro computer della storia compare sulla copertina di Practical Electronics. Un giovane di nome Bill Gates scrisse una versione di Basic per Altair ed ebbe un modesto seguito tra i primi utenti di queste macchine. Molte ditte iniziarono a costruire PC basati sul chip 8080; su di questi girava un SO chiamato CP/M (Control Program for Microcomputer) prodotto dalla DR (Digital Research), una piccola casa produttrice della California fondata da Gary Kildall. CP/M-86 per CPU INTEL 8086/8088. CP/M-8000 per CPU Z8000. CP/M-68K per CPU Motorola 68000. Tutti questi PC furono chiamati micro computer. PC IBM Intorno al 1980, l’IBM, decise che quella dei PC era un’area in cui avrebbe voluto operare; per cui fece qualcosa d’insolito per le normali burocrazie e precauzioni interne: incaricò uno dei suoi manager Philipe Estridge, di andare a Boca Raton, in Florida, duemila Km lontano da sguardi indiscreti, dalla Corporate Headquarter nel Westchester Country, nello stato di New York e gli disse di non tornare senza un PC. Estridge decise che il solo modo per produrre velocemente un PC era usare componenti standard, piuttosto che progettarne propri all’IBM, come aveva sempre fatto in passato. Nel frattempo l’INTEL aveva prodotto due successori dell’8080, l’8086 e una versione con un bus a 8 bit dell’8086, l’8088. Estridge scelse quest’ultimo perché era composto da chip che erano più economici. L’IBM, per il S/W, fece riferimento a Bill Gates, che nel frattempo aveva messo su una casa di S/W chiamata Microsoft e gli chiese la licenza dell’interprete Basic da usare sul PC IBM e chiese anche se avesse un SO per la macchina. Gates suggerì all’IBM di usare il CP/M-86 della DR, ma, dopo aver parlato con questi ultimi, scoprì che il CP/M-86 era ancora in fase di sviluppo e l’IBM non poteva attendere, allora IBM tornò alla Microsoft e chiese di sviluppare un SO simile al CP/M. Gates sapeva che non c’era il tempo necessario per prendere questo impegno, ma sapeva anche di una casa produttrice, la Seattle Computer Products, che aveva scritto un SO dello stesso tipo del CP/M, chiamato 86-DOS, per verificare i limiti di una memoria che aveva in produzione e in vendita. La Microsoft comprò 86-DOS; nell’aprile del 1981 assunse il suo autore, Tim Paterson, per migliorarlo; cambiò il nome del SO in MS-DOS e lo vendette all’IBM. Quando fu presentato, nell’agosto del 1981, il PC IBM era dotato del suo SO, l’MS-DOS, la virtù principale è che vi poteva girare la maggior parte del S/W che andava sull’8080 sotto CP/M. Se qualcuno avesse intuito che nel giro di dieci anni questo piccolo sistema, adottato quasi casualmente, avrebbe controllato cinquanta milioni di PC, avrebbe anche pensato di studiarlo più approfonditamente. Comunque, né l’IBM né nessun altro ebbe la percezione di quanto grande sarebbe stato il successo del PC IBM e, all’inizio, pensò che sarebbe stato usato per girare con i videogiochi a casa. MS-DOS um 2 di 138 Per esempio, il clock a 4.77 MHz fu scelto per essere compatibile con la frequenza dei televisori degli Stati Uniti, in modo tale che la gente potesse usare il monitor della TV invece che uno proprio del PC. La cosa più giusta che l’IBM fece fu di lasciare il PC come sistema aperto; infatti il progetto completo, compresi i listati della ROM (Read Only Memory) e gli schemi dei circuiti elettrici, erano descritti nei minimi particolari in un libro disponibile presso i rivenditori di PC. Questo significava che venditori S/W e H/W OEM potevano fare nuovi prodotti H/W e S/W da aggiungere al PC e fu ciò che fecero a migliaia. Infatti, con la disponibilità dei disegni dei circuiti e con la macchina interamente composta da componenti disponibili in commercio, alcune ditte cominciarono a costruire e a vendere delle copie del PC, chiamate cloni, in competizione diretta con la stessa IBM. Questa enorme profusione di energie e creatività portò al successo del PC e con esso al successo dell’MS-DOS. M S-DOS non era neppure incluso nell’acquisto del PC, si pagava a parte. Nel lancio iniziale, IBM non aveva fatto alcuno sforzo di marketing per spingere MS-DOS; l’accento era tutto sul PC. IBM si diede da fare a spiegare che vi erano ben tre SO disponibili per PC. 1. MS-DOS. 2. UCSD (University California San Diego) p-System, un sistema di sviluppo per programmatori, era un S/W del tipo “scritto una volta, gira dappertutto”. 3. CP/M-86, era arrivato in ritardo sul mercato ma la stampa riteneva che fosse superiore a MS-DOS. MicroPro aveva trasportato su CP/M-86 Word-Star, Ashton-Tate progettò una versione per il CP/M-86 di dBASE II. Però DR fece uno sbaglio colossale nel fissare il prezzo del CP/M-86 a 240 dollari, il prezzo di MS-DOS era di 40 dollari, l’enorme differenza di prezzo rese virtualmente impossibile vendere il CP/M-86 ai clienti finali e il SO sparì quasi subito. Versione 1.0 La prima versione dell’MS-DOS uscita nell’agosto del 1981 con il PC IBM era la versione 1.0, occupava 12 KB di RAM ed era compatibile con il CP/M. Il codice sorgente era formato da 4000 righe di codice assembly e il solo disco che supportava era un floppy disk da 5”1/4 da 160 KB. Il SO era formato da tre applicazioni. 1. IBMIO.COM, il sistema d’I/O del disco e dei caratteri. 2. IBMDOS.COM, il driver del disco e dei file. 3. COMMAND.COM, l’interprete dei comandi, una shell primitiva. A differenza di Unix, che era stato sempre completamente indipendente, MS-DOS ha sempre fatto uso di una ROM installata sul PC IBM, chiamata BIOS (Basic Input Output System) che contiene i driver per i dispositivi standard, per cui con una chiamata MS-DOS può gestire l’I/O. Laddove Unix contiene i driver per l’I/O da terminale, dai dischi, MS-DOS usava per gli stessi scopi il BIOS. La versione 1.0 utilizzava una sola directory, come il CP/M; al contrario persino la prima versione di Unix era fornita di un file system gerarchico. Aveva la capacità di gestire shell script molto semplici, chiamati batch file. Nell’ottobre del 1982, la Microsoft distribuì la versione 1.1 di MS-DOS, che supportava floppy disk da 320 KB. MS-DOS um 3 di 138 Il codice sorgente è disponibile, dal mese di marzo 2014, sul sito del Computer History Museum, fondato nel 1996 a Mountain View in California. Il file ZIP contiene quattro cartelle. 1. v11object: 27 file binari che costituiscono il sistema operativo. 2. v11source: 7 file in linguaggio assembly e l’email di Tim Paterson inviata a Len Shustek, il direttore del museo. 3. v20object: 38 file binari e documentazione. 4. v20source: 118 file in linguaggio assembly e documentazione. Versione 2.0 Nel marzo del 1983, l’IBM presentò il PC XT (eXtended Technology), il suo primo PC fornito di un disco fisso e con la nuova versione di MS-DOS, la 2.0 che rappresentava un taglio netto con il passato, occupava 24 KB di RAM. La Microsoft lo riscrisse interamente integrandolo con molte idee prese da Unix. Per esempio, il file system di MS-DOS fu basato molto su quello di Unix, con un piccolo numero di modifiche, per esempio, l’uso di (\) al posto di (/) come componente separatore. Erano presenti le chiamate di sistema OPEN, READ, WRITE e CLOSE nella stessa forma di Unix, utilizzando, in pratica, il descrittore di file non presente nella versione 1.0. Era migliorata la shell che poteva gestire la ridirezione dello standard I/O e supportava la pipeline e i filtri, floppy da 360 KB, i driver di dispositivi installabili dall’utente, lo SPOOL (Simultaneous Peripheral Operations On Line) di stampa, la possibilità di descrivere la configurazione del sistema, la gestione della memoria e la shell personalizzata. MS-DOS raggiunse la dimensione di 20000 righe di codice assembly ed eliminò decisamente il CP/M, autodefinendosi il SO dominante per il PC. Poiché il disco fisso offrì la possibilità di utilizzare molte applicazioni di grosse dimensioni, il PC XT trasferì l’interesse per i PC dall’ambiente casalingo al mondo degli affari. Piccole, medie e grandi imprese cominciarono ad acquistare i PC. Microsoft per le applicazioni commerciali dovette produrre la versione 2.05, che teneva conto anche dell’ora, della data, della valuta e dei simboli decimali di molte nazioni, per esempio il codice giapponese Kanji a sedici bit. Seguì a novembre dello stesso anno la 2.1 introdotta per il PC jr e infine mise insieme queste due ultime versioni sotto il nome di 2.11. Versione 3.0 Nell’agosto del 1984 l’IBM portò sul mercato il PC AT (Advanced Technology), basato sulla CPU 80286 con 16 MB di memoria, aveva il Kernel Mode e lo User Mode, una modalità di protezione e la capacità di eseguire più applicazioni contemporaneamente. La versione di MS-DOS, era la 3.0, non supportava nessuna di queste caratteristiche, al contrario girava in una modalità che simulava l’8088 ed era solo più veloce. Poiché il PC AT poteva utilizzare il floppy da 1.2 MB, un clock a batteria tampone e l’informazione di configurazione in CMOS (Complementary Metal Oxide Semiconductor), fu aggiunto un supporto per questi dispositivi. Inoltre, ora, erano supportati dischi fissi fino a 32 MB. In più, l’interprete dei comandi, la shell, fu rimossa dal SO e realizzata in un’applicazione separata, in modo che gli utenti la potessero sostituire con una versione personalizzata; tutto ciò fece aumentare le dimensioni del codice fino a 40000 righe. MS-DOS um 4 di 138 La versione 3.0 fu sostituita dalla 3.1 nel novembre del 1984 con la novità di fornire un supporto per le reti. La successiva fu la 3.2 presentata a gennaio del 1986; essa supportava floppy da 3”½ e la rete IBM Token Ring. Nel mese di aprile 1986 l’IBM portò sul mercato il successore della linea PC, la famiglia dei PS/2 (Personal System/2), presentata con floppy da 3”½ da 720 KB per le versioni più piccole e da 1.44 MB per quelle più grandi. Il PS/2 che era dotato della versione 3.3 supportava questi nuovi formati, altri formati internazionali e anche le linee seriali che operavano a 19200 bps (bit per secondo). Insieme con il PS/2 e la versione 3.3 di MS-DOS, l’IBM e la Microsoft distribuirono un SO completamente nuovo, chiamato OS/2 (Operating System). OS/2 avrebbe sostituito MS-DOS, ma ciò non accadde mai; infatti nonostante avesse molti vantaggi, come l’utilizzo completo della memoria, l’esecuzione in modalità protetta e la possibilità di adottare la multi programmazione, gli utenti non furono interessati al suo uso. Nel 1991, la Microsoft comunicò che stava disinteressandosi del tutto di OS/2, il che irritò talmente l’IBM da indurla a firmare un contratto con la Apple Computer quale fornitore del futuro S/W, interrompendo i contatti commerciali con la Microsoft. Versione 4.0 Constatando che il grosso successo atteso dell’OS/2 non avvenne mai, l’IBM sorprese tutti realizzando una nuova versione di MS-DOS, la 4.0, che successivamente la Microsoft riadattò per distribuirla ai costruttori di cloni PC. Questo evento fece intendere all’IBM che MS-DOS non stava scomparendo, così, invece di abbandonarlo, decise di renderlo decisamente migliore. Uno dei grossi miglioramenti introdotti in questa versione fu la capacità di gestire dischi fissi fino a 2 GB. Molti utenti, specialmente i principianti, nel migliore dei casi pensano che le linee di comando siano ermetiche e nel peggiore dei casi pensano che siano ostili, probabilmente anche peggio di Unix, la cui shell è stata raramente ritenuta piacevole per i principianti. Per rendere la vita più facile a queste persone, MS-DOS, a partire da questa versione, presentò un’alternativa: l’interfaccia orientata al video chiamata DOSSHELL. Essa elenca tutti i file e le directory in finestre e permette agli utenti di fare una notevole quantità di lavoro puntando e selezionando semplicemente con il mouse. Sebbene non sia un’interfaccia utente grafica ben chiara come Windows, questo è stato il primo passo in quella direzione. Versione 5.0 La versione 5.0 di MS-DOS fu presentata nell’aprile del 1991. Per la prima volta era fatto un uso serio della memoria estesa di cui molti proprietari di 80286 e 80386 avevano parecchi MB. Sebbene essa avesse la restrizione che le applicazioni non potevano eccedere i 640 KB, almeno aveva la capacità di allocare la maggior parte dell’MS-DOS stesso sulla memoria estesa, così circa 600 KB dei 640 KB erano disponibili per le applicazioni utente. Inoltre, i driver dei dispositivi scritti dagli utenti potevano essere messi anche nella memoria estesa. Questa versione aveva anche la capacità di usare la memoria tra 640 KB e 1 MB sulle macchine 80386 per i driver dei dispositivi e alcune applicazioni di utilità mettendo a disposizione molto di più di 640 KB, supportava floppy da 2.88 MB. Aveva l’applicazione DOSKEY, la history list di Unix, che poteva essere installata per recepire e bufferizzare tutte le battute dei tasti; intercettando le interruzioni da tastiera esaminava tutti i caratteri digitati prima che essi fossero passati al SO. In questo modo si potevano usare scorciatoie e altri accorgimenti passando righe precedenti di comando, con o senza editing, a COMMAND.COM come se essi giungessero direttamente dalla tastiera; inoltre riciclando i comandi precedenti, DOSKEY, MS-DOS um 5 di 138 permetteva agli utenti anche di definire della macro. In origine, MS-DOS era strettamente un sistema monotasking. Comunque, dalla versione 5.0, era possibile far partire un comando con un doppio clic sul nome di file e poi sospenderlo premendo CTRL+ESC. A questo punto ricompare la finestra DOSSHELL con il nome dell’applicazione sospesa nella finestra Lista dei processi Attivi; ora l’utente è libero di eseguire qualsiasi comando, compreso far partire un’altra applicazione, che a sua volta può essere sospesa allo stesso modo. Tutte le applicazioni sospese sono elencate in questa finestra e con un doppio clic su una di esse, l’applicazione prescelta riparte. Sebbene non sia la stessa cosa della multi programmazione è una buona seconda scelta. Questa versione offriva un’utility HELP di aiuto per gli utenti e molte nuove applicazioni di utilità e nuovi comandi. Per la prima volta, la versione 5.0 di MS-DOS fu venduta nei negozi, fino a quel momento tutte le versioni erano state vendute dai rivenditori di PC che le consegnavano insieme alle macchine e questo fu interpretato come un’assunzione di responsabilità da parte della Microsoft. Versione 6.0 La versione 6.0 di MS-DOS fu presentata nel 1993, include le seguenti caratteristiche. Comando SETUP per l’installazione. DOUBLESPACE, un’applicazione integrata di compressione dischi. MEMMAKER, un’applicazione di ottimizzazione della memoria che consente di spostare in modo semplice i driver di periferica e le applicazioni residenti in memoria dalla convenzionale all’area di memoria superiore. DEFRAG, un’applicazione che riorganizza i file sull’hard disk per ridurre il tempo di accesso del PC ai file. SCANDISK, per rilevare e correggere errori dei dischi. SMARTDRV, comando avanzato con cache per CD-ROM. MOVE, che sposta uno o più file da una directory o unità ad un’altra. DELTREE, che elimina una cartella, i suoi file e tutte le cartelle e i file ad essa subordinati. MSD (MicroSoft Diagnostics), che raccoglie e visualizza informazioni tecniche sul PC. INTERLNK, un’applicazione che semplifica il trasferimento di file tra PC. La Guida in linea sui comandi di tipo ipertestuale. BACKUP per Windows, MSAV antivirus per MS-DOS e per Windows, UNDELETE per Windows, CHOICE, DISKCOPY in una sola passata. Occupazione 6.3 MB. La possibilità di definire più configurazioni del sistema, particolarmente utile se si condivide il PC con più utenti, la possibilità di avviare il sistema senza eseguire CONFIG.SYS e AUTOEXEC.BAT: F5, di chiedere conferma per ciascun comando caricato: F8. Versione 7.0 Nel 1995 tecnicamente MS-DOS è del tutto obsoleto, però quando fu chiaro che l’OS/2 non avrebbe avuto seguito, la Microsoft fece una scelta diversa, sviluppando Windows come interfaccia grafica orientata al mouse con MS-DOS. D’altra parte, l’MS-DOS ha collezionato una grossa quantità di S/W ad alto livello. Implementazione MS-DOS è strutturato in tre livelli. 1. Il BIOS. 2. Il kernel. 3. La shell, COMMAND.COM. MS-DOS um 6 di 138 Il BIOS è un insieme di driver di dispositivo a basso livello che serve ad isolare MS-DOS dai particolari che riguardano l’H/W. Per esempio, il BIOS contiene le chiamate per leggere e scrivere dagli indirizzi assoluti del disco, per leggere un carattere dalla tastiera e per scrivere un carattere sul video. Il BIOS di solito è fornito dalle case produttrici di PC, piuttosto che dalla Microsoft e generalmente, in parte, è posto in una ROM nel segmento appena al di sotto del limite dello spazio degli indirizzi di 1 MB. Le routine BIOS sono chiamate mediante TRAP per mezzo del vettore d’interruzioni piuttosto che per mezzo di chiamate dirette di routine; ciò rende possibile al venditore di modificare la dimensione e la posizione delle routine BIOS nei nuovi modelli, senza dover rigenerare il SO. Il file IO.SYS, chiamato IBMIO.COM nella versione che consegna l’IBM, è un file nascosto presente su tutti i sistemi MS-DOS. Esso è caricato immediatamente dopo che è stato fatto il boot del PC e fornisce un’interfaccia di chiamate di routine a BIOS, per cui il kernel può accedere ai servizi di BIOS eseguendo le chiamate di routine ad IO.SYS invece che generare un TRAP nella ROM; inoltre questo file contiene le routine BIOS che non sono nella ROM e un modulo chiamato SYSINIT che è usato per fare il boot del sistema. È importante tenere presente che l’esistenza di IO.SYS isola ulteriormente il kernel dai particolari dell’H/W; per esempio, il kernel non deve sapere quale vettore si sta occupando di un certo servizio BIOS, poiché questi dettagli sono nascosti in IO.SYS. Il kernel è contenuto in un altro file nascosto, MSDOS.SYS, che l’IBM ha denominato IBMDOS.COM e contiene la parte indipendente dalla macchina del SO. Esso si occupa della gestione dei processi, della memoria e del file system e anche d’interpretare tutte le chiamate di sistema. La terza parte è formata dalla shell, il COMMAND.COM; naturalmente questa applicazione non appartiene al SO è può essere cambiata dall’utente. Il COMMAND.COM standard è formato da due parti. 1. La parte residente, che è sempre in memoria. 2. La parte transiente, che è in memoria solo quando la shell è attiva. La parte residente è posta in memoria subito dopo MSDOS.SYS e contiene gli interrupt 22H (Terminate Address), 23H (Ctrl-Break Handler) e 24H (Critical Error Handler). Quando l’applicazione è terminata, il codice di ritorno dell’applicazione stessa è usato per determinare se l’applicazione è sovrapposta alla parte transiente del COMMAND.COM. Se è così la parte residente ricaricherà la parte transiente dall’area indicata da COMSPEC=; se invece non è trovato il sistema si blocca. I messaggi di errore si trovano nella parte residente del COMMAND.COM. La routine d’inizializzazione è inclusa nella parte residente, assume il controllo durante lo startup e determina l’indirizzo dove l’applicazione dell’utente sarà caricata; essa sarà poi sovrapposta dalla prima applicazione caricata. La parte transiente è posta nella posizione finale superiore della memoria convenzionale e le applicazioni utente che hanno bisogno di spazio ci possono riscrivere sopra; quando il controllo ritorna a COMMAND.COM, questi controlla se la parte transiente è intatta, in caso contrario la ricarica. Contiene tutti i comandi interni; produce il prompt di MS-DOS, legge i comandi dallo standard input, keyboard o file batch e li esegue. Per i comandi esterni costruisce una linea di comando e una funzione EXEC che carica e trasferisce il controllo all’applicazione. I PC con MS-DOS sono inizializzati nel modo seguente: quando sono accesi oppure dopo un reset S/W CTRL+ALT+DEL o un reset H/W tasto di reset sul case, in questo caso riparte l’autodiagnostica, il controllo è trasferito all’indirizzo FFFF0H nella ROM che contiene un salto alla routine d’inizializzazione alla ROM BIOS. Questa routine effettua alcuni test e, se la macchina li passa, prova a leggere dal floppy A: MS-DOS um 7 di 138 nel settore di boot. Nel caso che non ci sia alcun floppy presente nel dispositivo A, è letto il settore principale di boot dell’hard disk se nessuno dei due dischi è trovato, il BIOS chiama l’interrupt 19H ROM Basic o visualizza un messaggio d’errore. La tabella di partizione in questo settore informa sulla posizione delle partizioni e su quale di essa è attiva, la partizione attiva è quindi selezionata e il suo primo settore, il settore secondario di boot, è letto ed eseguito. Questa procedura di boot a due passi è usata solo per i dischi rigidi; la sua funzione è quella di permettere un boot automatico sia di MS-DOS sia di altri SO. Il settore di boot legge la sua directory radice per vedere se IO.SYS e MSDOS.SYS sono presenti, nel qual caso li legge entrambi nella memoria e trasferisce il controllo ad IO.SYS. Una volta caricato, IO.SYS chiama la routine di BIOS per inizializzare l’H/W, dopodiché subentra SYSINIT e legge CONFIG.SYS per configurare il sistema. Questo lavoro comprende l’allocazione del buffer cache, il caricamento dei driver di dispositivo e la selezione delle pagine di codice per il linguaggio nazionale da utilizzare. Infine SYSINIT usa MS-DOS stesso per caricare ed eseguire COMMAND.COM, se la shell si trova in una sotto directory oppure è usato un processore di comando diverso questo deve essere specificato tramite il comando SHELL=STATEMENT in CONFIG.SYS. Esaminando tutto ciò si nota che SYSINIT fa lo stesso lavoro di init in Unix; dopo l’inizializzazione, il COMMAND.COM legge ed esegue AUTOEXEC.BAT, che è uno shell script ordinario per permettere all’utente di fare ciò che ritiene più opportuno. utilizzo Pochi comandi di base: semplicità. Standard: si adatta a diverse configurazioni H/W. Somiglianza con Unix. Vastissima disponibilità di strumenti. Monouser, Monotasking. Cartelle gerarchicizzate. MS-DOS può essere paragonato all’utilizzo di una delle prime versioni di Unix. C’è una shell, chiamata COMMAND.COM, un file system, le chiamate di sistema, le utility e altri aspetti che sono spesso simili a Unix, ma più primitivi. Per usare MS-DOS basta accendere il PC e poco dopo compare il prompt della shell. Non c’è alcun login o password, si sottintende che la macchina sia usata da un solo utente, quindi scarsa protezione. Per la stessa ragione, i file e le cartelle non hanno proprietari né bit di protezione e inoltre non esiste il superuser e un utente qualsiasi può fare qualsiasi cosa. In MS-DOS sono presenti alcune caratteristiche della shell di Unix e altre no. Per far girare un’applicazione basta digitare il nome e gli argomenti nella shell che fa una fork di un figlio, passa gli argomenti al figlio e rimane in attesa finché il figlio non ha finito l’esecuzione ed esce. Non è possibile mettere un carattere (&) alla fine della linea di comando per eseguire il comando in background, d’altra parte è permesso solo un comando per riga. In MS-DOS i comandi sono divisi in due categorie. 1. Interni circa quaranta sono eseguiti dalla shell stessa. 2. Esterni sono veri e propri utility che di solito si trovano nella cartella DOS. La realizzazione di molti comandi nella shell rappresenta un compromesso; da un certo punto di vista, non dovendo estrarli da un disco lento, li rende molto più veloci e, poiché il primo PC IBM non aveva hard disk, si può considerare senza dubbio questa ragione per cui i comandi furono inclusi nella shell. Da un altro punto di vista, tutto quel codice rende la shell più grande e per evitare che questo problema potesse sfuggire dalle mani, tutti i comandi interni sono stati mantenuti alle dimensioni minime possibili. MS-DOS um 8 di 138 Per esempio, non c’è alcuna possibilità di cancellare più file non correlati in una sola volta. I metacaratteri (*) e (?) sono presenti e sottintendono tutte le stringhe e un carattere rispettivamente, come in Unix. Il problema è che i metacaratteri funzionano solo per i comandi interni e non per quelli esterni ad eccezione di quelli che li gestiscono esplicitamente. In MS-DOS, la linea di comando è trasmessa all’applicazione così come è digitata, mentre in Unix è il risultato dell’espansione della linea di comando che è passata all’applicazione. Il risultato di tutto ciò è che gli utenti devono ricordare quali comandi gestiscono i metacaratteri e quali non li gestiscono; la cosa importante non è sapere chi fa l’espansione ma che questa sia fatta in modo non consistente. Il COMMAND.COM non fa distinzione tra maiuscole e minuscole. MS-DOS ha le cartelle di lavoro, ma esse differiscono da quelle di Unix in un aspetto importante: in Unix ogni processo ha la sua propria directory di lavoro. Se un utente digita cd /usr/ast/src e poi inizia un processo, questo eredita come cartella di lavoro /usr/ast/src, se il processo poi modifica la sua cartella di lavoro in /usr/ast/mail ed esce, la shell avrà come cartella di lavoro ancora /usr/ast/src e il processo successivo sarà allocato in quest’ultima. Al contrario, in MS-DOS, la stessa sequenza di eventi lascerà il secondo processo nella cartella MAIL poiché MS-DOS ha una sola cartella di lavoro; è tenuta traccia in una variabile globale kernel e quando questa variabile è modificata sono influenzati tutti i processi successivi e non solo quello corrente. La ridirezione dello standard input e output funziona come in Unix e usa anche la stessa notazione; per l’output il default è il video e si utilizza il simbolo (>). Esempio. C> dir>pippo <INVIO> C> dir>prn <INVIO> l’output va sul file di nome pippo l’output va su un dispositivo periferico, la stampante Se, invece, si utilizza il simbolo (>>) l’output è scritto dove termina il file precedente, operazione di append. Esempio. C> dir>\dev\nul <INVIO> Per l’input il default è la tastiera e si utilizza il simbolo (<), che preleva le informazioni da un file o da un altro dispositivo periferico. I filtri sono usati per leggere un input e trasformarlo secondo una certa funzione, il risultato è mandato in output. I comandi sono i seguenti. MORE: visualizza una pagina di video alla volta. SORT: ordinamento secondo il codice ASCII. FIND: ricerca in un file una particolare stringa. A>dir>record A>sort<record A>sort/r<record A>sort/+9<record A>sort/+9<record>prn A>find “17/02/71”record A>find/v “ESE1”record A>find/c “1”record A>find/n “BAT”record MS-DOS ordinamento crescente ordinamento decrescente ordinamento in colonna 9 ordinamento in colonna 9 ricerca una stringa um 9 di 138 A>find “ditta” <clienti.txt >salva.sav A>more<record A>more<record>prn Sono permesse le pipeline (canalizzazione di comandi) ma sono implementate in modo diverso con l’utilizzo di file temporanei. L’output di un comando è l’input del comando successivo. C> dir ¦ sort <INVIO> (pipe = alt 124). Sono ammessi più comandi pipe sulla stessa linea. C> dir ¦ sort ¦ more <INVIO> Il prompt dall’utente è un particolare simbolo, tipico di un dato ambiente, che contrariamente al cursore, quadratino o lineetta lampeggiante che si posiziona nel punto in cui andrà a collocarsi il carattere successivo, si posiziona sempre all’inizio della riga per indicare la disponibilità alla ricezione di comandi. Per esempio, nel linguaggio Basic il prompt è rappresentato dal simbolo OK, in MS-DOS esso è costituito dal simbolo [drive]:\>. Nomi di file riservati AUX CLOCK$ COM1,2,3,4 CON PRN LPT1,2,3 NUL uguale a COM1 device driver dell’orologio 1, 2, 3, 4 porta seriale console keyboard: input, display: output uguale a LPT1 1, 2, 3 porta parallela, la stampante nessun dispositivo, l’output è scartato configurazione MS-DOS può essere configurato in vari modi, per esempio, gli utenti sono liberi d’installare i driver d’interrupt, cosa non pensabile in Unix. La ragione di questa disparità è chiara, Unix è un sistema timesharing, con più utenti, per cui permettere loro d’inserire codice nel kernel, in qualsiasi momento, sarebbe un modo pericoloso di violare la sicurezza, in altre parole un invito a distruggere il sistema. In un sistema a utente singolo che non ha alcun tipo di sicurezza, il danno è inferiore. Un’altra forma di configurazione da parte dell’utente è la capacità d’installare i driver di dispositivo, questi possono gestire dispositivi non standard d’I/O, come i sintetizzatori di musica MIDI (Musical Instrument Digital Interface) e anche dispositivi standard, come memoria estesa, in modo non standard. Questa caratteristica fornisce un alto grado di flessibilità. Un tipo completamente differente di adattamento della configurazione riguarda l’area del linguaggio della nazione in cui è usato il PC, anche le configurazioni tradizionali delle tastiere differiscono da nazione a nazione. Per gestire le differenti tastiere, MS-DOS ha la capacità di mappare i codici dei tasti prodotti dalla tastiera in caratteri differenti, dipendenti, per esempio, dal fatto che il tasto a destra del TAB sia una “Q” negli Stati Uniti o una “A” in Francia; esso ha anche diversi file di codice di pagina CPI (Code Page File) installabili che contengono le mappe di bit per i 255 caratteri visualizzabili. Esiste anche una chiamata di sistema per permettere ad un’applicazione di chiedere una struttura che contiene l’informazione sui formati della data e dell’ora, sul simbolo corrente, MS-DOS um 10 di 138 il separatore numerico e altri oggetti che variano da nazione a nazione. Questa informazione permette alle applicazioni di accettare l’input e di produrre un output nella forma desiderata dall’utente, senza preoccuparsi del luogo in cui l’utente stesso vive. La maggior parte della configurazione di MS-DOS è gestita da un file chiamato CONFIG.SYS che è letto quando parte il sistema. Esso può contenere i comandi per installare i driver personali di dispositivo, definire il linguaggio nazionale, determinare dove mettere il SO in memoria, allocare memoria per il buffer cache, specificare il numero massimo di file aperti e scegliere la shell. I principali comandi sono: BREAK, BUFFERS, COUNTRY, DEVICEHIGH, DOS, FCBS, FILE, INSTALL, INTERLNK, LASTDRIVE, SET, SHELL, STACKS. I principali driver di periferica sono: ANSI.SYS. DISPLAY.SYS, DBLSPACE.SYS, EMM386.SYS, HIMEM.SYS, RAMDRIVE.SYS, SETVER.EXE. Inoltre, dopo che questo file è stato elaborato, è eseguito un batch file speciale chiamato AUTOEXEC.BAT per ulteriori inizializzazioni e configurazioni. I principali comandi sono: PROMPT, MODE, PATH, SET. Inoltre, è utilizzato per avviare i TSR (Terminate and Stay Resident), applicazioni che sono caricate nella memoria e vi risiedono, generalmente, fino a quando non si spegne il PC. I TSR forniti con MS-DOS sono: DOSKEY, VSAFE, SMARTDRV. La controparte in Unix si chiama .profile per la Bourne-Shell e .login per la C-Shell. Un blocco di configurazione inizia con un’intestazione di blocco [...], come nei file INI di Windows. File CONFIG.SYS [menu] definisce le scelte all’avvio menuitem = MS-DOS definisce una voce di menu menuitem = WORKGROUP menuitem = NOVELL menuitem = PATHWORKS menucolor = 14,1 imposta il colore del testo e di sfondo menudefault = NOVELL,10 parte dopo 10 secondi se non si fanno scelte [common] comandi comuni per tutte le configurazioni DEVICEHIGH=C:\DOS\SETVER.EXE DEVICE=C:\DOS\HIMEM.SYS DEVICE=C:\DOS\EMM386.EXE NOEMS BUFFERS=10,0 FILES=40 DOS=UMB FCBS=4,0 DOS=HIGH COUNTRY=039,850,C:\DOS\COUNTRY.SYS STACKS=9,256 SHELL=C:\DOS\COMMAND.COM C:\DOS\ /E:2048 /p INSTALLHIGH=C:\DOS\SHARE.EXE [ms-dos] [workgroup] [novell] comandi per la configurazione novell INSTALLHIGH=C:\NETWARE\LSL.COM INSTALLHIGH=C:\NETWARE\EWRK3.COM INSTALLHIGH=C:\NETWARE\IPXODI.COM [pathworks] DEVICE=\TCPIP\PROTMAN.SYS /I:C:\TCPIP DEVICE=\TCPIP\NEMM.DOS DEVICE=\TCPIP\EWRK3.DOS DEVICE=\TCPIP\TCPDRV.DOS /I:C:\TCPIP MS-DOS um 11 di 138 LASTDRIVE=Z File AUTOEXEC.BAT @echo off LOADHIGH C:\DOS\SMARTDRV.EXE LOADHIGH C:\DOS\DOSKEY.COM LOADHIGH C:\WINDOWS\MOUSE.COM /Y LOADHIGH C:\DOS\KEYB IT,,C:\DOS\KEYBOARD.SYS PROMPT $p$g PATH C:\WINDOWS;C:\;C:\DOS;C:\NETWARE; SET TEMP=C:\DOS GOTO %CONFIG% variabile associata alla scelta di menu :MS-DOS CLS DATE TIME GOTO END :WORKGROUP CLS GOTO END :NOVELLLOADHIGH C:\NETWARE\NETX.COM F: LOGIN STUDENTI CLS C: GOTO END :PATHWORKS SET PATH=%PATH%;C:\TCPIP;D:PCAPP; CALL \TCPIP\STARTNET :END MS-DOS attrib chdir (cd) cls comp copy date del (erase) dir edit fc find help mkdir (md) more print rename rmdir (rd) set type MS-DOS Unix chmod cd, pwd clear cmp copy, cp date rm ls, lc, ll vi diff grep man mkdir more, pg lp, lpr mv rmdir $set, %env cat DESCRIZIONE Visualizza o modifica gli attributi dei file. Visualizza il nome o cambia la cartella corrente. Pulisce lo schermo. Confronta il contenuto di due file. Copia uno o più file. Visualizza o modifica la data corrente. Elimina i file specificati. Elenca i file e le cartelle. Editor. Confronta due file e ne visualizza le eventuali differenze. Ricerca una determinata stringa di testo in un file. Manuale on-line. Crea una nuova cartella. Visualizza l’output una schermata alla volta. Stampa un file di testo. Cambia il nome di un file. Elimina una cartella. Visualizza, imposta o rimuove le variabili di ambiente. Visualizza il contenuto di un file di testo. um 12 di 138 chiamate di sistema Alcune delle chiamate di sistema di MS-DOS sono simili a quelle di Unix, ma altre sono completamente diverse. Le chiamate di sistema sono fatte mediante un TRAP al kernel, con l’utilizzo di un vettore 21H e mettendo il numero della chiamata di sistema nel registro AX, poche altre utilizzano altri vettori. Una libreria d’interfaccia delle chiamate di sistema è fornita dal C e da altri compilatori per permettere ai programmatori di linguaggio ad alto livello di fare le chiamate in modo opportuno come in Unix. Un buon numero di applicazioni MS-DOS scrivono sul vettore 21H un puntatore nel loro codice, che permette loro di accettare e d’ispezionare tutte le chiamate di sistema. Alcune di queste chiamate sono gestite in maniera diversa, di solito per estendere in un qualche modo MS-DOS; la parte rimanente consiste in un salto all’indirizzo che il vettore 21H conteneva nella prima posizione. Sebbene sia fornita una chiamata di sistema per leggere e scrivere i vettori d’interrupt, la tecnica non è portabile su altri sistemi o architetture e causerà problemi se MS-DOS o i suoi successori dovessero supportare anche la multiutenza. Di fatto è una misura di emergenza per raggiungere funzionalità o tranelli che dovrebbero essere messi nel SO sin dall’inizio. Per rendere possibili le reti, per esempio, spesso s’implementa ulteriore codice di rete con con TSR che accetta tutte le chiamate di sistema e ne ispeziona ognuna per vedere se essa richiede un accesso remoto. Quelle che lo richiedono sono gestite dal TSR e quelle che non lo richiedono sono restituite a MS-DOS. Le chiamate al sistema permettono di scrivere applicazioni indipendenti dall’H/W, machine independent e con compatibilità con versioni successive di MS-DOS. Sollevando il programmatore da incombenze quali la costruzione di apposite routine per la lettura da disco, la gestione del file system, le chiamate di sistema rendono contemporaneamente la gestione del sistema più sicura, ed efficiente. Categorie di system calls Standard character device I/O. Memory management. Process management. File and directory management. Microsoft Network calls. Miscellaneous system functions. SEQUENZE DI ESCAPE C> PROMPT $E[65;112P $E[ prompt indica che i successivi caratteri costituiscono una sequenza di escape. 65 è il codice ASCII del tasto da ridefinire, in questo caso A. (;) è l’elemento separatore tra due codici ASCII. 112 è il codice ASCII del carattere che apparirà al posto del primo, in questo caso P. P è l’elemento che indica il termine della sequenze di escape, tra i caratteri non ci devono essere blank e/o <INVIO>. clrscr(); gotoxy (); printf (“%c[2J”,27); printf (“%c[%d;%dH”,27,x,y); In questo modo possono essere assegnati valori e stringhe di caratteri anche a quei tasti MS-DOS um 13 di 138 che non hanno un proprio valore specifico, tipo i tasti funzione: INS, DEL, ALT, SHIFT, CTRL e i tasti del tastierino numerico. Per esempio affinché il comando DIR sia lanciato premendo il tasto F10 bisogna usare la sequenza seguente. C>PROMPT $E[0;68;”dir”;13P In cui 0;68 è il codice ASCII del tasto F10, 13 il codice ASCII del tasto INVIO. Funzioni MS-DOS: spostamento cursore, clrscr, grafica. Per utilizzarle è necessario introdurre nel CONFIG.SYS ed eseguire il seguente comando. device = ansi.sys. A>prompt $E [97;109;101;108;97; P prompt A>a A>prompt $E [97;97;P prompt Per ripristinare il prompt invece di digitarlo basta mettere a fine sequenza. $p$g: PROMPT $E[H$p$g Cursore in 0,0. C>PROMPT $E[31;1;5m CIAO MONDO PROMPT $E[37;0m$p$g File PROVA.BAT REM assegnazione di F1 PROMPT $E [0;59;”2”;13P REM assegnazione di F2 PROMPT $E [0;60;”8”;13P PROMPT $E [H$E[K$E[7M TURBOPASCAL F1$E [8C LOTUS F2$E[24;1H COMANDO : $E[0M$E[K. A>prompt $ E [7M$T$E[M #include <stdio.h> #include <conio.h> #define GOTO(x,y) cprintf(“%c[%d;%dH”,27, y, x) #define HAUT cprintf(“%c[1A”,27) #define BAS printf(“%c[1B”,27) #define DROITE printf(“%c[1C”,27) #define GAUCHE printf(“%c[1d”,27) #define SAUVE printf(“%c[s”,27) #define RAPPELLE printf(“%c[u”,27) #define CLS printf(“%c[2J”,27) #define DLN printf(“%c[K”,27) #define NORM printf(“%c[0m”,27) #define SURB printf(“%c[1m”,27) #define CLIG printf(“%c[5m”,27) #define INVS printf(“%c[7m”,27) #define SOULI printf(“%c[4m”,27) int main(void) { CLS; NORM; printf(“Stampa normale,\n\n “); SURB;printf(“un po’ di blink.\n\n”); NORM;SOULI; cprintf(“Testo sottolineato e colorato,\n\n “); NORM;CLIG; printf(“e intermittente.\n\n”); MS-DOS um 14 di 138 NORM;INVS;printf(“Video inverso ...\n”); NORM; getch();return (0); } BATCH Altre caratteristiche prese da Unix sono le variabili di shell e gli script, chiamati file batch, in MS-DOS ma sono molto più deboli di quelli usati in Unix. Evitano d’immettere sequenze ripetitive di comandi e offrono la possibilità di creare delle procedure standard, in altre parole personalizzano il SO. Hanno una struttura procedurale: CALL, ECHO, FOR, GOTO, IF, PAUSE, REM, SHIFT. Non sono in grado di leggere i messaggi di errore su video: sono ciechi, assumono che il comando abbia funzionato alla perfezione e usano alla cieca il successivo. La macchina virtuale, formata da MS-DOS più l’H/W, è programmabile, ovvero è in grado di eseguire una sequenza di operazioni. Uno script batch è formato da un insieme di comandi del SO scritti in un file di testo. MS-DOS riconosce un file batch mediante l’estensione BAT. L’operatore per scrivere uno script batch deve digitare l’insieme delle istruzioni che vuole eseguire in un file di testo scritto, ad esempio, con l’editor interno del SO. Per eseguire un file batch è sufficiente digitare il suo nome, senza l’estensione BAT, al prompt dei comandi; dopodiché MS-DOS inizia ad interpretare e ad eseguire un’istruzione dopo l’altra a partire dalla prima, uno script batch è quindi un’applicazione sorgente eseguita da MS-DOS, mediante il suo interprete dei comandi. Questa modalità è diversa da quella relativa alle applicazioni eseguibili EXE e COM, che sono caricate in memoria centrale dal SO e in seguito eseguite dalla CPU. Un file eseguibile, in linguaggio macchina, è quindi un codice compilato, mentre un file batch di testo è uno script interpretato da DOS. La macchina DOS può quindi essere utilizzata dall’operatore in due modalità. 1. Interattiva. 2. Batch o a lotti. Nel modo interattivo, l’operatore interagisce direttamente con la macchina, fornendo comandi mediante l’interfaccia interprete e verificando immediatamente il risultato ottenuto. Questo tipo di attività è “interattiva”, perché l’uomo dialoga direttamente con il sistema. Nella modalità batch, lo script è eseguito in modo automatico da MS-DOS senza l’intervento dell’operatore, il quale non può in alcun modo intervenire se l’applicazione non è terminata. L’uso della modalità batch, letteralmente a lotti o in parti, consente di trasformare un utente in un programmatore DOS. Questa modalità è utile ogniqualvolta si devono programmare alcune attività ripetitive, mediante “un lotto” di comandi, dove non è richiesto direttamente l’intervento dell’operatore. Script batch È un insieme d’istruzioni scritte, una per ogni riga, in un file di testo in formato ASCII, che la macchina DOS esegue in modo sequenziale, una dopo l’altra. Un file batch non può avere lo stesso nome di uno eseguibile, perché, per convenzione, MS-DOS esegue sempre i file EXE e COM prima di quelli batch. Alcuni comandi, denominati batch, utilizzabili esclusivamente in questo tipo di script, che realizzano le funzioni seguenti. L’input di alcuni parametri. Il controllo dell’output delle istruzioni, ECHO. MS-DOS um 15 di 138 L’introduzione di commenti, REM. Il controllo del flusso dello script IF, GOTO, PAUSE, CALL. Creazione dei file batch. 1. Edit. 2. COPY CON:[FILENAME].BAT <INVIO> ------------ CTRL+Z <INVIO>. Durante l’esecuzione di uno script batch, per visualizzare messaggi sullo schermo si utilizza il comando seguente. ECHO messaggio Dove messaggio è il testo che si vuole presentare. ECHO seguito da un punto, presenta una riga vuota, iniziando a scrivere in quella successiva. Durante lo svolgimento dello script batch, MS-DOS visualizza sia le istruzioni, che sta eseguendo, sia i loro risultati. ECHO OFF Annulla l’output sul video dei comandi eseguiti da MS-DOS. Per annullare anche la visualizzazione dello stesso ECHO OFF si usa la sintassi. @ECHO OFF Per riprendere la visualizzazione dei comandi si deve fornire il comando seguente. ECHO ON Quando MS-DOS incontra un comando non valido non lo esegue passando all’istruzione successiva, in questo caso l’operatore, può interrompere l’esecuzione dello script digitando contemporaneamente CTRL+C. In alcuni casi può essere conveniente sospendere l’esecuzione dello script, anche solo momentaneamente, utilizzando il comando PAUSE. L’esecuzione è ripresa quando l’operatore digita un qualsiasi tasto. Esempio: nello script batch precedente quando si cambia l’unità attiva da C ad A, se nel drive non è presente un floppy il SO sospende l’esecuzione del comando. Prima di cambiare l’unità corrente si può avvertire l’operatore con un messaggio, ECHO e sospendere momentaneamente l’esecuzione con PAUSE. REM commento Consente d’inserire nel file dello script un commento, quando l’interprete dei comandi incontra REM, iniziale di REMark, ignora tutti i caratteri successivi posti sulla stessa riga. I commenti sono utili sia per rendere leggibile uno script batch a persone diverse dagli autori, sia per lo stesso autore quando, dopo un certo tempo, deve riprendere il file per modificarlo. Per fornire un input ad uno script batch, ogni applicazione specifica l’elaborazione da eseguire sui dati d’ingresso per passare ai risultati, nel caso di script batch. I risultati sono gli effetti delle operazioni, quali ad esempio, la copia di un file su disco oppure la visualizzazione sullo schermo del contenuto di una cartella con DIR. I dati in ingresso sono invece i parametri delle istruzioni. Le variabili batch, o parametri sostituibili, sono nove variabili predefinite che il SO mette a disposizione del programmatore DOS e indicate, per convenzione, con i simboli da %1 MS-DOS um 16 di 138 fino a %9. Ognuna delle variabili precedenti può essere utilizzata in uno script batch per contenere il valore del parametro di un comando. I valori delle variabili batch sono introdotti dall’operatore quando digita il nome dello script. Esempio, lo script batch RINOMINA.BAT. REN %1 %2 Consente di cambiare il nome di un file con la sintassi seguente. REN nome_vecchio nome_nuovo Digitare. A:\>RINOMINA CAMBIAD.DAT CAMBIA_DIR.DAT Assegna i valori CAMBIAD.DAT e CAM_DIR.DAT alle variabili batch %1 e %2. Esegue il comando REN con i nuovi parametri. In questo modo, l’operatore può creare delle istruzioni personalizzate. Il numero 1 che individua una variabile batch in %1, rappresenta l’ordine con cui devono essere introdotti i parametri dall’operatore quando digita il nome dello script batch. L’interprete MS-DOS esegue le istruzioni in uno script batch in sequenza. Vi sono alcuni comandi batch che consentono di alterare l’ordine sequenziale di esecuzione, ad esempio, saltando l’esecuzione di alcune righe oppure richiamando all’interno dello script un altro file batch. In uno script batch, l’esecuzione può essere trasferita nei modi seguenti. 1. All’interno dello stesso script. 2. All’esterno, ad un altro file batch. GOTO etichetta Trasferisce, nello stesso script, l’esecuzione alla riga individuata dal parametro etichetta preceduto da un due punti (:etichetta). Richiamare all’interno di uno script batch un altro script. 1. Scrivere in una linea il nome dei file batch da richiamare. 2. Utilizzare il comando CALL nome_file_batch Se si usa il comando CALL, l’interprete MS-DOS richiama il file batch esterno e, dopo averne terminato l’esecuzione, ritorna allo script batch chiamante riprendendo l’esecuzione dalla linea successiva che contiene CALL. Se invece si richiama un file batch solo con il suo nome, MS-DOS lo esegue terminando l’esecuzione dello script chiamante. IF condizione comando Esegue il comando, di norma GOTO, solo se la condizione è vera, TRUE, viceversa l’interprete ignora l’istruzione. La condizioni più frequenti sono le seguenti. 1. La verifica del valore assunto da una variabile batch, con la sintassi: IF “%1”==“VALORE” COMANDO. 2. Verifica dell’esistenza di un file, con il formato IF EXIST NOMEFILE COMANDO che esegue il comando solo se esiste nella directory corrente il file con il nome indicato. Esempio, progettare un menu. È possibile creare un menu che permette all’operatore di effettuare delle scelte e quindi automatizzare le procedure di gestione dell’elaboratore. MS-DOS um 17 di 138 La gestione dei clienti di una azienda in un disco con la seguente struttura. Può essere organizzata creando con l’editor del DOS in ogni cartella di livello inferiore dei file con lo stesso nome ELENCO.TXT, ma contraddistinti dal loro percorso. Ad esempio, il file ELENCO.TXT nella cartella \EUROPA\PRODOTTO.B contiene l’elenco dei clienti europei del prodotto B. Per la gestione del disco con i clienti, si possono creare due script batch nella cartella radice di A. Il primo, MENU.BAT, presenta sullo schermo il menu e consente all’operatore di effettuare una scelta, mentre il secondo, SCELTA.BAT, apre effettivamente i file elenco con l’editor del DOS. File MENU.BAT CLS @ECHO OFF ECHO GESTIONE CLIENTI ECHO Scelta dell'elenco: ECHO. ECHO 1. Italia: prodotto A ECHO 2. Italia: prodotto B ECHO 3. Europa: prodotto A ECHO 4. Europa: prodotto B ECHO 5. Extra Europa: prodotto A ECHO 6. Extra Europa: prodotto B ECHO 7. Fine script PROMPT Digitare SCELTA seguito dal numero: Il comando PROMPT cambia la riga di comando dell’interprete indicando all’operatore la sintassi per richiamare lo script batch SCELTA.BAT. File SCELTA.BAT @ECHO OFF IF %1 ==1 I:\ITALIA\PRODOTTO.A IF %1 ==2 I:\ITALIA\PRODOTTO.B IF %1 ==3 I:\EUROPA\PRODOTTO.A IF %1 ==4 I:\EUROPA\PRODOTTO.B IF %1 ==5 I:\EXTRAEUROPA\PRODOTTO.A IF %1 ==6 I:\EXTRAEUROPA\PRODOTTO.B REM ****** Scelta fine script batch ******************************** IF %1 ==7 GOTO FINE REM ****** Apro l'elenco clienti ******************************** MS-DOS um 18 di 138 REM con l'editor di MS-DOS EDIT ELENCO.TXT REM ****** Prima di richiamare MENU.BAT e' necessario rendere REM attiva la cartella radice dove si trovano i documenti. MENU REM ****** Fine script batch ******************************** :FINE PROMPT $p$g Dopo aver aperto il file ELENCO.TXT con i clienti, lo script visualizza nuovamente il menu richiamando il file batch MENU.BAT. Eseguendo lo script. I:\>MENU <INVIO> E digitando al nuovo prompt dei comandi è richiamato il file SCELTA.BAT che apre l’editor per il file ELENCO.TXT nel catalogo I:\ITALIA \PRODOTTO.A. Se s’introduce SCELTA con l’opzione sette lo script termina. File TEST1.BAT REM collegamenti tra file batch ECHO sono in TEST1 CALL TEST2 ECHO sono ancora in TEST1. File TEST2.BAT REM collegamenti tra file batch ECHO sono in TEST2. File MYFILE.BAT REM è possibile parametrizzare sequenze di comandi, i parametri vanno da %0 a %9 REM vanno specificati ad ogni richiamo, il parametro %0 è il il nome del file batch copy %1 %2 type %2 type %0.bat c>MYFILE A:prog1 B:prog2 <INVIO> copy A:prog1 B:prog2 type B:prog2 type MYFILE.BAT. File 1.BAT REM uso del comando ECHO è in on per default ECHO OFF MS-DOS um 19 di 138 CLS REM questo messaggio non è visualizzato REM questo sì indipendentemente dal valore di ECHO ECHO Ciao, mondo! ECHO ON REM ECHO e’ di nuovo in on File 2.BAT REM uso del comando GOTO REM prima linea REM seconda linea GOTO fine REM terza linea : FINE REM quarta linea Se si aspetta un parametro dopo il nome del file batch, il controllo è il seguente. IF %1==GOTO FINE File 3.BAT REM uso del comando IF ECHO OFF IF %1==rosa GOTO UNO IF %1==profumo GOTO DUE ECHO sei nei guai GOTO FINE : UNO ECHO che pensiero gentile GOTO FINE : DUE ECHO come sei romantico : FINE File 4.BAT REM vuoi entrare in pascal (y/n) MS-DOS um 20 di 138 ECHO OFF IF %1==n GOTO FINE turbo : FINE File 5.BAT :LOOP IF %1==“ GOTO FINE DIR C: %1 SHIFT ;slitta ai valori successivi GOTO LOOP :FINE ; c>5 ws turbo basic File ECO.BAT ECHO %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 ECHO riferimento 1 SHIFT ECHO %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 ECHO riferimento 2 SHIFT ECHO %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 ECO 1 2 3 4 5 6 7 8 9 10 11 ECO 1 2 3 4 5 6 7 8 9 riferimento 1 1 2 3 4 5 6 7 8 9 10 riferimento 2 2 3 4 5 6 7 8 9 10 11 Esempio, progettare un nuovo comando, CAMBIA.BAT che cambi il nome ad un file con un nome qualsiasi ed estensione DA (NOMEFILE.DA), modificando l’estensione in .A (NOMEFILE.A). SET nome1=%1.DA SET nome2=%1.A ECHO Cancello %nome2% ... IF EXIST %nome2% DEL %nome2% ECHO ... e chiamo %nome1%, %nome2% REN %nome1% nome2% Esempio, stampare l’elenco di tutti i file di una cartella. ECHO OFF cmd.exe /d /c dir %1 /o >lista.txt ECHO ON Esempio, eliminare i file WAV, LOG e INI dalla cartella RECENT. ECHO OFF for %%t in (wav log ini) do del "%userprofile%\Recent\*.%%t" ECHO Fatto! Ripulita la cartella Recent ECHO ON MS-DOS um 21 di 138 PROCESSI Introduzione In Unix i concetti che riguardano i processi e la memoria sono chiaramente separati e sono indipendenti dalla macchina. I processi possono creare processi figli usando la chiamata di sistema fork e possono modificare la dimensione del loro segmento di dati usando la chiamata di sistema brk; nessuno di questi dipende in alcun modo dall’architettura di base della macchina. In MS-DOS, il modello di un processo e l’uso della sua memoria sono strettamente connessi e notevolmente molto vincolati ai dettagli dell’architettura delle iAPx86 e del sistema PC IBM. Inoltre, il modello del programmatore dei processi e la memoria non sono separabili per l’implementazione. Per esempio, collocare un processo negli indirizzi 0400H e 0800H è diverso e il programmatore deve stare in guardia sulle diverse proprietà di ognuno di essi. MS-DOS non è un sistema multiprogrammato come Unix e non può supportare più processi contemporaneamente. Non è nemmeno un sistema a monoprogrammazione: esso sta a metà tra questi due tipi di sistemi. Quando s’inizializza il sistema, un processo, il COMMAND.COM parte e attende un input. Quando è digitata una riga, il COMMAND.COM fa partire un nuovo processo mediante la funzione 4B00H, alloca memoria, scrive un PSP (Program Segment Prefix) per la nuova applicazione all’offset zero della memoria allocata, carica la nuova applicazione e le passa il controllo aspettando finché non abbia finito. Come si vede, ciò non è diverso da Unix, dove la shell normalmente attende che un processo sia completato prima di dare il prompt. La differenza consiste nel fatto che, in Unix, qualsiasi utente è libero di scrivere una shell che non attende e che dà subito il prompt. Inoltre, la shell standard non deve attendere se l’utente mette un (&) dopo il comando; ad ogni modo, in Unix, dopo la partenza di un processo figlio, il genitore non deve attendere poiché può continuare l’esecuzione in parallelo con il figlio. In MS-DOS il genitore e il figlio non possono girare in parallelo; quando un processo fa una fork di un figlio, il genitore è automaticamente sospeso finché il figlio non termina e il genitore non può fare nulla per evitare ciò. Vi possono essere molti processi presenti in memoria, ma solo uno di essi è attivo, i rimanenti sono sospesi in attesa che un figlio finisca. Per questo motivo, sebbene MS-DOS permetta a molti processi di esistere contemporaneamente, esso non è un vero sistema a multiprogrammazione. È possibile, in ogni caso “barare” e raggiungere un grado limitato di multiprogrammazione manipolando direttamente le strutture dati del SO. Questo trucco funziona solo perché MS-DOS gira su macchine che non hanno o non usano la protezione della memoria. MS-DOS ha due tipi di file binari, che danno origine a due tipi differenti di processi. File con estensione COM (Core iMage) massima priorità È un semplice file eseguibile, esso non ha intestazione e ha un solo segmento. Il file eseguibile è un’immagine esatta byte per byte del codice eseguibile; il file è caricato nella memoria così com’è ed è eseguito, non è rilocabile, è compatto e caricato velocemente. Questo tipo di modello di processo proviene dal CP/M. MS-DOS um 22 di 138 Un processo generato da un file COM ha un segmento di codice, più dati e più stack lungo non più di 64 KB e COMMAND.COM gli alloca tutta la memoria disponibile e inizializza lo stack pointer a 100H in cima al segmento da 64 KB. Se il processo non prevede di fare una fork dei figli, esso può girare così, mentre, se ne prevede, esso deve restituire la parte non usata di memoria al SO con una chiamata di sistema INT 48H. Se tralascia di liberare memoria, il tentativo di fare una fork di un figlio fallirà e quindi il sistema si ferma, HALT e deve essere resettato. Se un COM che non ha ancora rilasciato parte della memoria fornitagli dal sistema, ne richiede altra, riceverà quell’occupata dalla parte residente di COMMAND.COM che dovrà essere ricaricato a processo ultimato. Per minimizzare questo rischio un’applicazione COM deve ridurre il blocco che il sistema gli ha allocato inizialmente INT 4AH e rilasciare tutta la memoria allocata. C:\> DEBUG <INVIO> -A 0D0D:0100 MOV AH,2 <INVIO> 0D0D:0102 MOV DL ,7<INVIO> 0D0D:0104 INT 21H <INVIO> 0D0D:0106 INT 20H <INVIO> 0D0D:0108 <INVIO> - U 100L8 <INVIO> 0D0D:0100 B402 MOV AH,02 0D0D:0102 B207 MOV DL,07 0D0D:0104 CD21 INT 21 0D0D:0106 CD20 INT 20 -R AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D0D ES=0D0D SS=0D0D CS=0D0D IP=0100 NV UP EI PL NZ NA PO NC 0D0D:0100 B402 MOV AH,02 -T AX=0200 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D0D ES=0D0D SS=0D0D CS=0D0D IP=0102 NV UP EI PL NZ NA PO NC 0D0D:0102 B207 MOV DL,07 -T AX=0200 BX=0000 CX=0000 DX=0007 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D0D ES=0D0D SS=0D0D CS=0D0D IP=0104 NV UP EI PL NZ NA PO NC 0D0D:0104 CD21 INT 21 -P AX=0207 BX=0000 CX=0000 DX=0007 SP=FFEE BP=0000 SI=0000 DI=0000 DS=0D0D ES=0D0D SS=0D0D CS=0D0D IP=0106 NV UP EI PL NZ NA PO NC 0D0D:0106 CD20 INT 20 -P Programma terminato regolarmente - N beep.com <INVIO> - R CX <INVIO> CX 0000 : 8 <INVIO> - W <INVIO> - Q <INVIO> C:\> DEBUG BEEP.COM 012345 <INVIO> - R <INVIO> AX=0000 BX=0000 CX=0008 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 MS-DOS um 23 di 138 DS=0D7A ES=0D7A SS=0D7A CS=0D7A IP=0100 NV UP EI PL NZ NA PO NC Sicuramente il valore esadecimale dei segmenti sul PC sarà diverso da quello di quest’esempio, questo perché MS-DOS carica DEBUG e qualsiasi altra applicazione eseguibile a partire dal primo segmento libero trovato in memoria. Gli eseguibili di tipo COM presentano la caratteristica di avere i quattro registri di segmento allineati sul primo segmento trovato libero in memoria da MS-DOS. - D 0D7A:0000L100 0D7A:0000 CD 20 FF 9F 00 9A F0 FE-1D F0 4F 03 51 07 8A 03 . ........O.Q... 0D7A:0010 51 07 17 03 51 07 40 07-01 01 01 00 02 FF FF FF Q...Q.@......... 0D7A:0020 FF FF FF FF FF FF FF FF-FF FF FF FF 1E 0D 4C 01 ..............L. 0D7A:0030 31 0C 14 00 18 00 7A 0D-FF FF FF FF 00 00 00 00 1.....z......... 0D7A:0040 05 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0D7A:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 30 31 32 .!...........012 0D7A:0060 33 34 35 20 20 20 20 20-00 00 00 00 00 20 20 20 345 ..... 0D7A:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........ 0D7A:0080 07 20 30 31 32 33 34 35-0D 4D 20 30 31 32 33 34 . 012345.M 01234 0D7A:0090 35 0D 30 0D 73 65 20 64-65 6C 20 53 6F 75 6E 64 5.0.se del Sound 0D7A:00A0 20 42 6C 61 73 74 65 72-20 6E 6F 6E 20 76 61 6C Blaster non val 0D7A:00B0 69 64 6F 2E 20 41 64 20-65 73 65 6D 70 69 6F 3A ido. Ad esempio: 0D7A:00C0 0D 69 63 61 72 65 20 75-6E 20 69 6E 64 69 72 69 .icare un indiri 0D7A:00D0 7A 7A 6F 0D 2E 30 2E 0D-00 00 00 00 00 00 00 00 zzo..0.......... 0D7A:00E0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0D7A:00F0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ - Q <INVIO> I primi 256 byte da 0000H a 00FFH, 16 paragrafi di ogni processo MS-DOS formano un blocco speciale, il PSP e anche quest’idea è stata presa direttamente dal CP/M. Il PSP è costruito dal SO al momento della creazione del processo. Per i file COM, esso occupa una parte di spazio degli indirizzi del processo e può essere indirizzato utilizzando gli indirizzi da 0 a 255; per questa ragione, tutti i processi COM iniziano da 100H e non dall’indirizzo 0. Il PSP contiene la dimensione dell’applicazione, un pointer al blocco di ambiente, l’indirizzo del gestore di CTRL+C, la stringa di comando, un pointer al PSP del genitore, la tabella dei descrittori dei file e tutta una serie d’informazioni destinate a MS-DOS, per controllare l’applicazione in esecuzione; creato da INT 4B00H. I tre interrupt che iniziano all’offset 0AH permettono al processo padre di eseguire il processo figlio. L’indirizzo del gestore di CTRL+C può essere cambiato dall’applicazione. Quando l’utente digita CTRL+C per interrompere il processo corrente, è chiamato questo gestore, il meccanismo è analogo a quello con cui Unix gestisce sigint. Il buffer della coda di comando inizia all’offset 80H e può contenere al massimo 127 byte, il primo byte riporta il numero di caratteri introdotti dopo il comando, escluso il CR (Carriage Return) che è in ogni caso memorizzato nel buffer. I caratteri introdotti da tastiera sono, quindi, memorizzati a partire dall’offset 81H, sono tolti il nome dell’applicazione chiamata ed eventuali comandi di ridirezione d’I/O. Può essere sfruttato vantaggiosamente ogni volta che un’applicazione contiene dei parametri passati insieme al nome dell’applicazione stessa. Il PSP è creato automaticamente dalla funzione Execute Program; Load Overlay, invece, non costruisce il PSP in quanto l’overlay è considerato come un segmento che fa parte dell’applicazione chiamante e che quindi non ha bisogno di una struttura PSP autonoma. MS-DOS um 24 di 138 OFFSET 00H 02H 04H 05H 0AH 0EH 12H 16H 2CH 2EH 50H 52H 5CH 6CH 80H 81H -D 0D7A:0100 0D7A:0110 0D7A:0120 0D7A:0130 0D7A:0140 0D7A:0150 0D7A:0160 0D7A:0170 SIZE 2 2 1 5 4 4 4 16 2 22 2 0A 10 14 1 7F CONTENUTI INT 20 (CODICE OPERATIVO CDH) SEGMENTO FINE BLOCCO ALLOCAZIONE RISERVATO CHIAMATA ALLA VECCHIA FUNZIONE DOS CS:IP INT 22H (PROGRAM TERMINATE ADDRESS) CS:IP INT 23H (CTRL-C) CS:IP INT 24H (CRITICAL ERROR) PARENT PROGRAM SEGMENT PREFIX POINTER ALL’ENVIRONMENT BLOCK (SET DI MS-DOS) RISERVATO INT 21H RISERVATO FCB1 FCB2 LUNGHEZZA CODA COMANDO CODA COMANDO B4 02 B2 07 CD 21 CD 20-6F 6E 74 72 6F 6C 6C 6F .....!. ONTROLLO 20 64 69 20 43 54 52 4C-2B 43 20 73 75 70 70 6C DI CTRL+C SUPPL 65 6D 65 6E 74 61 72 65-2E 0D 0A 0D 0A 42 52 45 EMENTARE.....BRE 41 4B 20 5B 4F 4E 20 7C-20 4F 46 46 5D 0D 0A 0D AK [ON | OFF]... 0A 44 69 67 69 74 61 74-6F 20 73 65 6E 7A 61 20 .DIGITATO SENZA 70 61 72 61 6D 65 74 72-69 2C 20 42 52 45 41 4B PARAMETRI, BREAK 20 76 69 73 75 61 6C 69-7A 7A 61 20 6C 27 69 6D VISUALIZZA L’IM 70 6F 73 74 61 7A 69 6F-6E 65 20 63 6F 72 72 65 POSTAZIONE CORRE Ci sono prima i dati, in questo esempio non ci sono dati, poi il codice macchina dell’applicazione, la corrispondenza dei byte che rappresentano istruzioni in linguaggio macchina corrispondono al disassemblato, comando U. EB (Environment Block) Contiene una copia dedicata all’applicazione dell’ambiente DOS. Precede sempre l’applicazione, non possiede dimensione fissa, ma è fissata al momento del caricamento; contiene tutte le variabili della shell nella forma VARIABILE = VALORE. Si visualizza/memorizza con SET, ogni entry dell’ambiente è una stringa ASCII chiusa da un byte uguale a 0: questo formato è chiamato ASCIIZ e termina con il carattere ASCII 0. Rispetto all’ambiente, MS-DOS si comporta come Unix, tranne per il fatto che in Unix il puntatore d’ambiente non è posto ad un indirizzo prefissato, ma è un parametro del main. Al termine dell’insieme delle variabili di ambiente, iniziano i processi di ambiente caricati con COMMAND.COM o in risposta ad EXEC. COMSPEC=C:\COMMAND.COM0 PROMPT=$p$g0 0 0001 C:\PROVA\PROVA.EXE0 Esempio di variabili di ambiente in un PC. CONFIG=DOS COMSPEC=C:\DOS\COMMAND.COM BLASTER=A220 I5 D1 T4 SOUND=C:\SBPRO MS-DOS um 25 di 138 PROMPT=$P$G PATH=C:\;C:\DOS;C:\WINDOWS;C:\UT;C:\SBPRO\PLAYCD;C:\TP\BIN;C:\BORLANDC\B IN;C:\LLHOME TEMP=C:\WINDOWS\TEMP TMP=C:\WINDOWS\TEMP LLHOME=C:\LLHOME DOSSEG .MODEL TINY .CODE ORG 100H BEGIN: MOV AH,2 MOV DL,7 INT 21H MOV AX,4C00H INT 21H END BEGIN .ASM = 164 byte .OBJ = 194 byte .COM = 10 byte CODE SEGMENT ASSUME CS:CODE, DS:CODE, ES:CODE, SS:CODE ORG 100H BEGIN: MOV AH,2 MOV DL,7 INT 21H MOV AX,4C00H INT 21H CODE ENDS END BEGIN .ASM = 195 byte .OBJ = 137 byte .COM = 10 byte SP = FFFE STACK 64 KB 0110 inizia lo stack perchè non ci sono dati CODE PSP CODE CODE DATA DATA STACKSEG MS-DOS IP = 0100 CS, DS, ES, SS = 0AB7 SEGMENT ENDS SEGMENT ENDS SEGMENT um 26 di 138 STACKSEG ENDS GRP GROUP STACKSEG, DATA, CODE CODE SEGMENT ASSUME CS:GRP, ES:GRP, DS:GRP, SS:GRP ORG 100H BEGIN: MOV AH,2 MOV DL,7 INT 21H MOV AX,4C00H INT 21H CODE ENDS END BEGIN Due o più segmenti in un’unità logica per essere indirizzata da un solo segmento. .ASM = 324 byte .OBJ = 217 byte .COM = 76 byte File con estensione EXE (EXEcutable) Un processo creato da uno di questi file può avere un segmento di codice, uno di dati, uno di stack e molti segmenti extra così come ritiene necessario. A differenza dei file COM, i file EXE contengono informazioni di rilocazione, in modo che possono essere rilocati al volo quando sono caricati. Il SO riconosce la differenza tra i file guardando i primi due byte e non guardando l’estensione del nome di file. I file EXE sono rilocati prima del PSP, così l’indirizzo 0 è il primo byte prima del PSP e questa strategia evita di perdere 256 byte dello spazio degli indirizzi. DOSSEG .MODEL SMALL STACK 200H .DATA .CODE BEGIN: MOV AX,@DATA MOV DS,AX MOV AH,2 MOV DL,7 INT 21H MOV AX,4C00H INT 21H END BEGIN .ASM = 217 byte .OBJ = 404 byte .EXE = 256 (PSP) + 31 (CODE) + 256 (RILOCAZIONE) = 543 byte Gli eseguibili EXE presentano la caratteristica di mantenere separate, anche fisicamente, le tre aree logiche di CODE, DATA e STACK dell’applicazione per sfruttare pienamente le capacità di gestione segmentata della memoria. C:\> DEBUG BEEP.EXE <INVIO> MS-DOS um 27 di 138 - R < INVIO > DS = ES = 0AB7 CS = 0AC7 SS = 0AC9 IP=0010 salta i primi 16 byte AX = BX = DX = BP = SI = DI = 0000 CX = 001F (31D) SP=0200 - Q < INVIO > 0AB7:0000 = DS, ES:0000 0AB7:0000 = DS, ES:00FF (PSP, in DS non ci sono dati) 0AB7:0100 = CS:0000 (0AB70 + 0100 = 0AC70) 0AB7:0110 = CS:001F (perchè CX = 1F) 0AB7:0120 = SS:0000 (0AB70 + 0120 = 0AC90) 0AB7:0320 = SS:0200 SP = 0200 STACK SS = 0AC9 CODE IP = 0010 .................................. CS = 0AC7 ..... DS, ES = 0AB7 PSP STACKSEG SEGMENT STACK ‘STACK’ DB 200 DUP (?) STACKSEG ENDS DATA SEGMENT DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:CODE, ES:CODE, SS:STACKSEG BEGIN: MOV AX,DATA MOV DS,AX MOV AH,2 MOV DL,7 INT 21H MOV AX,4C00H INT 21H CODE ENDS END BEGIN .ASM = 312 byte .OBJ = 198 byte .EXE = 256 (PSP) + 527 (CODE) + 256 (RILOCAZIONE) = 1039 byte c:\> debug beep.exe <INVIO> - R <INVIO> DS = ES = 0AB7 CS = 0AE7 SS = 0AC7 IP=0000 AX = BX = DX = BP = SI = DI = 0000 CX = 020F (527D) SP=0200 - Q <INVIO> 0AB7:0000 = DS, ES:0000 0AB7:0000 = DS, ES:00FF (PSP, in DS non ci sono dati) 0AB7:0100 = SS:0000 (0AB70 + 0100 = 0AC70) MS-DOS um 28 di 138 0AB7:02F0 = SS:0200 0AB7:0300 = CS:0000 0AB7:050F = CS:020F (0AB70 + 0300 = 0AE70) CODE IP = 0000 CS = 0AE7 SP = 0200 STACK PSP SS = 0AC7 DS, ES = 0AB7 Quando un’applicazione è caricata sono richieste informazioni per il calcolo della memoria necessaria e l’assegnazione dei valori iniziali ai diversi registri. Queste informazioni si trovano nella struttura file header, che è costruita dal linker ed è collocata all’inizio dei file di tipo EXE. In fase di caricamento il sistema prova ad allocare la memoria indicata da MAXALLOC, se questo non è possibile, cerca allora di assegnare tutta la memoria disponibile, purché questa abbia almeno le dimensioni indicate in MINALLOC, se anche questo tentativo non ha successo, il caricamento è interrotto. Per questo motivo MAXALLOC riceve spesso il valore FFFFH, in modo da assicurare che il SO allochi al processo tutta la memoria disponibile. Al file header fa seguito una tabella di rilocazione, relocation table, per il calcolo degli indirizzi assoluti in funzione del punto di caricamento e infine il codice compilato dell’applicazione vera e propria. Dato che è pronto per il caricamento, un file di tipo EXE è chiamato anche modulo di caricamento, load module. OFFSET 00H 02H 04H 06H 08H 0AH 0CH 0EH 10H 12H 14H 16H 18H 1AH 1CH variabile variabile variabile CONTENUTI Identificatore del tipo di file 4DH, 5AH, <M,Z>, Mark Zbikowski “Piccolo, ma onnipresente monumento posto a ricordo di se stesso”. Numero di byte contenuti nell’ultima pagina, lunghezza file modulo 512. Lunghezza del file in pagine di 512 byte, header compreso. Numero dei riferimenti presenti nella tabella di rilocazione. Lunghezza file header in paragrafi da 16 byte. Numero minimo di paragrafi necessari al programma: MINALLOC. Numero massimo di paragrafi richiesti dal programma: MAXALLOC. Valore iniziale di SS (Stack Segment) da rilocare. Valore iniziale di SP (Stack Pointer). Somma di controllo sulle word del file: CRC (Cyclic Redundancy Check). Valore iniziale di IP (Instruction Pointer). Valore iniziale di CS (Code Segment) da rilocare. Offset del primo elemento della tabella di rilocazione. Numero di overlay, è uguale a zero per la parte residente del programma. Riservato. Tabella di rilocazione. Riservato. Programma e dati. In MS-DOS un processo qualsiasi può essere caricato direttamente passando il suo nome all’interprete di comandi oppure all’interno di un altro processo in esecuzione. MS-DOS um 29 di 138 La tabella di rilocazione è formata da un numero variabile di oggetti da rilocare, ognuno dei quali è formato da due campi: un offset, 2 byte e un numero di segmento, riferiti a una word che richiede modifica prima che il controllo sia passato al modulo caricato. 1. La parte formattata dello header è trasferita in memoria, 1BH byte. 2. Una porzione di memoria allocata in rapporto alla dimensione del modulo di caricamento e di MINALLOC e MAXALLOC, MS-DOS tenta di allocare FFFFH paragrafi per ottenere la dimensione del massimo blocco disponibile; se essa è minore di MINALLOC e MAXALLOC, sarà segnalato un errore; se il blocco è maggiore di MAXALLOC, MS-DOS allocherà un blocco pari a (MAXALLOC + dimensione del blocco da caricare), altrimenti il sistema allocherà il blocco libero più grosso. 3. Il PSP costruito nella parte inferiore della memoria allocata. 4. La dimensione del load module valutata in base alle informazioni contenute nei campi 04H-05H, 08H-09h e 02H-03H dello header; il loader localizza in memoria il segmento appropriato dove caricare il load module, start segment. 5. Il load module è trasferito in memoria a partire dallo start segment. 6. La tabella di rilocazione è trasferita in un’area di lavoro in RAM. 7. Per ogni elemento della tabella di rilocazione, si aggiunge il valore dello start segment al campo segmento; il valore calcolato, più il contenuto del campo offset, un puntatore a una word nel load module alla quale aggiungere il valore dello start segment; il nuovo valore della word è infine riscritto nell’immagine in memoria del load module, questo procedimento è la rilocazione. 8. I registri SS e SP sono inizializzati come indicato nei campi 0EH-0FH e 10H-11H; il loader incrementa poi SS del valore dello start segment; i registri ES (Extra Segment) e DS (Data Segment) sono inizializzati con l’indirizzo di segmento del PSP; infine il valore dello start segment aggiunto al valore iniziale per CS indicato nello header; il risultato, insieme al valore iniziale per IP, campo 14H-15H, il punto iniziale CS:IP al quale trasferire il controllo per iniziare l’esecuzione dell’applicazione. Un file EXE è convertito in COM con il comando seguente EXE2BIN. Un figlio, in MS-DOS, di solito eredita i file aperti dal genitore e le loro posizioni, a meno che i file non siano aperti con una modalità speciale per inibire che siano ereditati. Se un figlio legge o scrive un file aperto, quando esce, il genitore vede la nuova posizione del file e può passarla al figlio successivo. Qualsiasi file aperto dal figlio è automaticamente chiuso quando esce e la memoria è liberata. Un figlio può anche restituire uno stato di uscita al suo genitore; tutte queste caratteristiche sono esattamente le stesse di Unix. A differenza di Unix, MS-DOS non supporta alcun tipo di paginazione o swapping. Quando un processo fa una fork di un figlio, vi è pericolo che non ci sia sufficiente memoria per il figlio e per i suoi discendenti. Per ridurre la probabilità che ciò accada, molti processi che possono avere figli sono costruiti in due parti. Nella prima figura si vede il sistema subito dopo l’inizializzazione e dopo che è partito il COMMAND.COM; nella successiva si vede la stessa dopo che è stato fatto partire l’EDIT. Si supponga che l’editor permetta all’utente di tornare al COMMAND.COM senza perdere il contesto di EDIT. In Unix, l’editor creerà una shell con una fork e lascerà che il sistema lo scarichi; questa soluzione in MS-DOS è impossibile. L’editor probabilmente sarà costituito da una piccola applicazione di avvio (stub) e dall’editor stesso. Prima di fare una fork di COMMAND.COM, l’editor può copiare la sua immagine di memoria su un file su disco e ridurre la sua allocazione di memoria in modo che contenga solo lo stub e poi fare la fork, ottenendo così la terza situazione in figura. Se l’utente decide di formattare un floppy si ottiene la situazione indicata nell’ultima figura. Quando l’applicazione di formattazione termina, si torna alla situazione immediatamente MS-DOS um 30 di 138 precedente. Quando l’utente digita EXIT per uscire da COMMAND.COM, lo stub dell’editor prende di nuovo il controllo e legge la parte rimanente del suo processo affinché possa continuare da dove era stato interrotto. Di solito quando un processo esce, la sua memoria è recuperata e il processo scompare definitivamente. MS-DOS ha anche una modalità alternativa per cui un processo che esce dà istruzioni al SO di non riprendere la memoria che ha usato, ma di trattarlo in modo diverso. Questa caratteristica ha generato una piccola industria: costruzione e vendita del S/W TSR. CARICAMENTO DI UN OVERLAY Quando un’applicazione richiede il caricamento di un overlay, deve indicare a MS-DOS l’indirizzo del segmento nel quale l’overlay dovrà essere trasferito. L’applicazione chiamante potrà poi richiamare l’overlay, che restituirà infine il controllo all’applicazione chiamante stessa. MS-DOS non controlla se l’applicazione chiamante possiede la memoria dove l’overlay è caricato, perciò è possibile che un uso incauto di INT 4B03H distrugga un blocco di controllo della memoria causando uno stato di inconsistenza della struttura logica della RAM e un possibile errore di allocazione. Perciò un’applicazione che carica un overlay deve adattare la sua capacità di memoria alla dimensione dell’overlay stesso. chiamate di sistema A differenza di Unix, MS-DOS non fa alcuna distinzione tra le chiamate di sistema fork ed exec; le funzioni di entrambi sono combinate nella chiamata LOAD_AND_EXECUTE. In Unix la ragione per cui esse sono divise è quella di permettere di manipolare i descrittori di file dopo la fork, ma prima della exec. In MS-DOS, la shell prima salva i suoi descrittori di file, poi sistema quelli del figlio e quindi lo esegue. Quando il figlio termina, la shell memorizza nuovamente i descrittori del file. Il primo parametro denomina il file binario e il secondo è un puntatore ad una struttura che contiene i puntatori alla linea di comando e all’ambiente. La chiamata LOAD_OVERLAY è simile alla precedente, eccetto che l’overlay non è fatto partire; esso è solo caricato in memoria e dipende dal genitore decidere se chiamare qualche procedura nell’overlay con una chiamata di procedura ordinaria. La chiamata END_PROCESS equivale alla chiamata exit di Unix, ma KEEP_PROCESS esiste solo in MS-DOS; quindi, quando un’applicazione termina, non distrugge la sua immagine di memoria e resta residente. MS-DOS um 31 di 138 Perché non vi sia una chiamata di sistema WAIT, il genitore ha bisogno di un altro modo per sapere il valore dello stato restituito dal figlio; a ciò si ovvia con una chiamata di sistema GET_RETURN_CODE_OF_CHILD_PROCESS, che restituisce lo stato del figlio che è stato eseguito per ultimo. FUNZIONE 4BH Categoria Gestione processi. 1) load and execute Descrizione L’applicazione è caricata e passata direttamente in run. Input AX = 4B00H DS:DX = punta al file da caricare come processo. ES:BX = punta ad un record contenete i parametri della funzione. 2) load overlay Descrizione L’applicazione è caricata come overlay, ma non è eseguita. Input AX = 4B03H DS:DX = punta al file da caricare come processo. ES:BX = punta ad un record contenete i parametri della funzione. In entrambi i casi il modulo di sistema provvede al rilocamento del codice rispetto all’inizio dell’area di caricamento, calcolando i nuovi indirizzi e riferimenti. 31H Keep process 4CH End process 4DH Get return code of child process 62H Get PSP implementazione La gestione dei processi in MS-DOS è semplice perché non c’è multiprogrammazione. Quando un processo attiva una chiamata di sistema LOAD_AND_EXECUTE, MS-DOS esegue i seguenti passi. 1. Trova un blocco di memoria sufficientemente grande per contenere un processo figlio; per un file EXE, la dimensione si può dedurre dall’informazione nell’intestazione; per uno COM è allocata tutta la memoria disponibile, ma l’applicazione può restituire la memoria non usata nel caso ciò sia richiesto. 2. Inserisce il PSP nei primi 256 byte di memoria allocata; alcune delle informazioni sono dal PSP del genitore e altre informazioni, come la linea di comando, sono uniche per questo processo; un puntatore che ritorna al PSP del genitore del processo è compreso nel PSP del figlio, in un certo senso il PSP è analogo alla struttura utente in Unix. 3. Carica il file binario eseguibile nella memoria allocata iniziando dal primo byte al di sopra del PSP; per i file EXE si deve aggiungere una costante di rilocazione a tutti gli indirizzi rilocabili; per i COM non cambia nulla. 4. Fa partire l’applicazione, l’indirizzo di partenza di un EXE è contenuto nell’intestazione; quello di un file COM è l’indirizzo 0100H per saltare oltre il PSP. I PSP hanno un ruolo importante in MS-DOS. Una variabile globale nel sistema punta al PSP del processo corrente. Il PSP contiene tutte le informazioni di stato necessarie per eseguire il processo; poiché il PSP contiene il puntatore di ritorno al PSP del genitore, dato il puntatore a quello corrente, MS-DOS può eseguire la catena all’indietro fino al COMMAND.COM e localizzare tutti i processi, sospesi, nel sistema. Il PSP contiene anche l’indirizzo a cui ritornare dopo l’uscita. Il puntatore che MS-DOS mantiene al PSP del processo corrente ha un ruolo importante anche nella programmazione TSR. Le chiamate di sistema non documentate servono per leggere e scrivere questo puntatore, permettendo ad un programmatore TSR di salvare il puntatore del PSP corrente e d’installare il suo. Fatto ciò, il TSR può chiamare MS-DOS per fare l’I/O al suo posto. MS-DOS um 32 di 138 Questo trucco funziona solo se accade che l’applicazione utente, piuttosto che il SO, è attivo al momento in cui prende il controllo il TSR. Ad ogni modo è disponibile un’altra chiamata di sistema per scoprire quale era attivo, permettendo al TSR di posticipare il suo lavoro finché la chiamata di sistema corrente, se ne esiste una, è terminata. In alternativa, il TSR può localizzare il puntatore al segmento dei dati interni di MS-DOS e sviarlo su un altro, facendo in modo che il sistema “dimentichi” momentaneamente ciò che stava facendo. Utilizzare chiamate di sistema di questo genere è una pratica pericolosa e poco pulita, anche se virtualmente tutti i TSR funzionano in questo modo. La schedulazione della CPU è banale poiché c’è un solo processo attivo che è eseguito continuamente, tranne quando un TSR prende il controllo. File RUN.ASM Mostra come sia possibile caricare un processo da parte di un altro già in esecuzione per mezzo della funzione LOAD_OVERLAY, accetta come parametro il nome di un’applicazione, alloca uno spazio di memoria sufficiente a contenerla, costruisce un PSP, carica il processo come overlay e infine gli passa il controllo dell’esecuzione. La memoria da allocare al nuovo processo è calcolata addizionando la dimensione del modulo di caricamento, la dimensione minima di memoria stimata necessaria indicata in MINALLOC, la dimensione dello stack e infine 10H paragrafi (256 byte) per il PSP del nuovo processo. Dato che molti dei parametri presenti nel PSP non sono strettamente necessari all’esecuzione e altri devono coincidere con quelli originali del processo chiamante, il nuovo PSP è costruito per semplicità copiando quello già esistente. Una volta dato inizio alla nuova applicazione, RUN non ottiene più il controllo dell’esecuzione. ;caricamento di un processo come overlay e sua esecuzione stackseg segment para stack ‘stack’ db 200h dup (?) stackseg ends end_process macro mov al,1 mov ah,4ch int 21h endm data segment word ‘data’ file_name db 20h dup (0) file_header db 1ch dup (0) ;buffer per il file header par_block db 04h dup (0) ;parametri programma local_psp dw 0 file_handle dw 0 ;handle per il file in ingresso req_mem dw 0 ;memoria richiesta area_ptr dw 0 ;indica l’inizio dell’area assegnata al nuovo processo load_ptr dw 0 ;indica il punto di caricamento di overlay 10 paragrafi oltre;l’inizio dell’area ssegnata new_ss dw 0 ;stack segment nuovo file new_sp dw 0 new_cs dw 0 ;code segment nuovo file new_ip dw 0 ;prima istruzione nel nuovo processo data ends cseg segment word ‘cseg’ assume cs:cseg,ds:data,ss:stackseg MS-DOS um 33 di 138 begin: mov ax,ds mov bx,data mov ds,bx mov local_psp,ax reduce_memory: mov bx,100h mov ah,4ah int 21h jnc get_file_name end_process get_file_name: cld mov di,offset file_name mov ax,data mov es,ax mov ax,local_psp mov ds,ax mov si,80h lodsb xor ah,ah mov cx,ax loop_1: lodsb cmp al,32 ja copy_inp_string dec cx jmp loop_1 copy_inp_string: stosb dec cx rep movsb open_file_handle: mov ax,data mov ds,ax mov dx,offset file_name mov ah,3dh mov al,0h int 21h jnc read_from_file end_process read_from_file: mov file_handle,ax mov bx,ax mov dx,offset file_header mov cx,28 mov ah,3fh int 21h jnc close_file_handle end_process close_file_handle: mov bx,file_handle mov ah,3eh int 21h jnc request_memory MS-DOS ;il psp è contenuto in ds ;es punta al psp di run ;riduzione con set_block della memoria allocata ;256 paragrafi = 4kbyte es punta al psp di run ;esce se tutto ok cf = 0 ;lettura filename via linea comando ;si e di vanno incrementati ;es:di punta a file_name ;ds = local_psp via ax ;ds:di punta alla stringa di comando ;lunghezza della stringa in al ;cx = numero di byte da leggere ;eliminazione blank dalla stringa d’ingresso ;controllo primo char valido ;ascii > 32 (spazio) ;byte da leggere -1 ;legge char successivo ;lettura stringa d’ingresso ;es:di punta già a file_name ;copia byte successivi, numero in cx ;apertura del file in lettura ;ds:dx punta a file_name ;risultato chiamata da ax ;handle per il file ;ds:dx punta a file_header ;numero byte da leggere ;uscita se ok cf = 0 ;uscita se ok cf = 0 um 34 di 138 end_process request_memory: ;calcolo memoria da allocare al nuovo processo mov ax,word ptr file_header[4] mov cx,32 ;conversione paragrafi mul cx ;ax * 32 add ax,word ptr file_header[0ah] ;memoria minima da allocare add ax,word ptr file_header[10h] ;spazio richiesto dallo stack add ax,10h ;10 paragrafi = area psp del processo mov req_mem,ax ;memoria richiesta in paragrafi mov bx,ax ;memoria richiesta in bx mov ah,48h ;funzione dos allocate_memory int 21h jnc make_new_psp ;uscita se ok cf = 0 end_process make_new_psp: mov area_ptr,ax ;ax pointer all’area libera add ax,10h ;spazio richiesto da psp mov load_ptr,ax ;segmento di caricamento di overlay mov es,area_ptr ;il psp del processo padre è copiato nel figlio mov di,0 mov ds,local_psp mov cx,100h rep movsb ;copiatura mov ax,data mov ds,ax load_new_program: ;caricamento overlay mov bx,load_ptr ;costruzione parameter block mov word ptr par_block[0],bx mov word ptr par_block[2],bx mov ax,data mov es,ax mov bx,offset par_block ;es:bx punta a parameter block mov dx,offset file_name ;ds:dx punta a file_name mov ah,4bh mov al,03h int 21h jnc new_registers ;uscita se ok cf = 0 end_process new_registers: ;calcolo i registri per il nuovo processo mov ax,word ptr file_header[0eh] add ax,load_ptr ;ss iniziale è rilocato rispetto a inizio area caricamento mov new_ss,ax mov ax,word ptr file_header[10h] mov new_sp,ax ;sp iniziale non è rilocato mov ax,word ptr file_header[16h] add ax,load_ptr ;cs iniziale è rilocato rispetto a inizio area caricamento mov new_cs,ax mov ax,word ptr file_header[14h] mov new_ip,ax ;ip iniziale non è rilocato mov bx,new_cs ;caricamento registri per esecuzione nuovo processo mov cx,new_ip cli mov ax,new_ss ;passaggio al nuovo stack mov ss,ax MS-DOS um 35 di 138 mov ax,new_sp mov sp,ax mov ax,area_ptr mov ds,ax mov es,ax pushf push bx push cx iret cseg ends end begin ;ds es puntano al psp del nuovo processo ;new_cs nuovo segmento codice ;new_ip nuovo pointer all’istruzione ;passaggio al nuovo processo File PARENT.ASM Usa l’EXEC per caricare ed eseguire un child process di nome CHILD.EXE. stdin equ 0 ; standard input stdout equ 1 ; standard output stderr equ 2 ; standard error stksize equ 128 ; size of stack cr equ 0dh ; ASCII carriage return lf equ 0ah ; ASCII linefeed DGROUP group _DATA,_ENVIR,_STACK _TEXT segment byte public ‘CODE’ ; executable code segment assume cs:_TEXT,ds:_DATA,ss:_STACK stk_seg dw ? ; original SS contents stk_ptr dw ? ; original SP contents main proc far ; entry point from MS-DOS mov ax,_DATA ; set DS = our data segment mov ds,ax ;now give back extra memory; so child has somewhere to run... mov ax,es ; let AX = segment of PSP base mov bx,ss ; and BX = segment of stack base sub bx,ax ; reserve seg stack - seg psp add bx,stksize/16 ; plus paragraphs of stack mov ah,4ah ; fxn 4AH = modify memory block int 21h jc main1 ; display parent message ... mov dx,offset DGROUP:msg1 ; DS:DX = address of message mov cx,msg1_len ; CX = length of message call pmsg push ds ; save parent’s data segment mov stk_seg,ss ; save parent’s stack pointer mov stk_ptr,sp ; now EXEC the child process mov ax,ds ; set ES = DS mov es,ax mov dx,offset DGROUP:cname ; DS:DX = child pathname mov bx,offset DGROUP:pars ; EX:BX = parameter block mov ax,4b00h ; function 4BH subfunction 00H int 21h ; transfer to MS-DOS cli ; (for bug in some early 8088s) mov ss,stk_seg ; restore parent’s stack pointer mov sp,stk_ptr sti ; (for bug in some early 8088s) pop ds ; restore DS = our data segment jc main2 ; jump if EXEC failed otherwise EXEC succeeded, MS-DOS um 36 di 138 ; convert and display child’s termination and return codes... mov ah,4dh ; fxn 4DH = get return code int 21h ; transfer to MS-DOS xchg al,ah ; convert termination code mov bx,offset DGROUP:msg4a call b2hex mov al,ah ; get back return code mov bx,offset DGROUP:msg4b ; and convert it call b2hex mov dx,offset DGROUP:msg4 ; DS:DX = address of message mov cx,msg4_len ; CX = length of message call pmsg ; display it mov ax,4c00h ; no error, terminate program int 21h ; with return code = 0 main1: mov bx,offset DGROUP:msg2a ; convert error code call b2hex mov dx,offset DGROUP:msg2 ; display message ‘Memory mov cx,msg2_len ; resize failed...’ call pmsg jmp main3 main2: mov bx,offset DGROUP:msg3a ; convert error code call b2hex mov dx,offset DGROUP:msg3 ; display message ‘EXEC mov cx,msg3_len ; call failed...’ call pmsg main3: mov ax,4c01h ; error, terminate program int 21h ; with return code = 1 main endp ; end of main procedure b2hex proc near ; convert byte to hex ASCII ; call with AL = binary value BX = addr to store string push ax shr al,1 shr al,1 shr al,1 shr al,1 call ascii ; become first ASCII character mov [bx],al ; store it pop ax and al,0fh ; isolate lower 4 bits, which call ascii ; become the second ASCII character mov [bx+1],al ; store it ret b2hex endp ascii proc near ; convert value 00-0FH in AL add al,’0’ ; into a “hex ASCII” character cmp al,’9’ jle ascii2 ; jump if in range 00-09H, add al,’A’-’9’-1 ; offset it to range 0A-0FH, ascii2: ret ; return ASCII char. in AL ascii endp pmsg proc near ; displays message on standard output ; call with DS:DX = address CX = length mov bx,stdout ; BX = standard output handle mov ah,40h ; function 40h = write file/device MS-DOS um 37 di 138 int 21h ; transfer to MS-DOS ret ; back to caller pmsg endp _TEXT ends _DATA segment para public ‘DATA’ cname db ‘CHILD.EXE’,0 ;pathname of child process pars dw _ENVIR ; segment of environment block dd tail ; long address, command tail dd fcb1 ; long address, default FCB #1 dd fcb2 ; long address, default FCB #2 tail db fcb1-tail-2 ; command tail for child db ‘dummy command tail’,cr fcb1 db 0 ; copied into default FCB #1 in db 11 dup (‘ ‘) ; child’s program segment prefix db 25 dup (0) fcb2 db 0 ; copied into default FCB #2 in db 11 dup (‘ ‘) ; child’s program segment prefix db 25 dup (0) msg1 db cr,lf,’Parent executing!’,cr,lf msg1_len equ $-msg1 msg2 db cr,lf,’Memory resize failed, error code=‘ msg2a db ‘xxh.’,cr,lf msg2_len equ $-msg2 msg3 db cr,lf,’EXEC call failed, error code=‘ msg3a db ‘xxh.’,cr,lf msg3_len equ $-msg3 msg4 db cr,lf,’Parent regained control!’ db cr,lf,’Child termination type=‘ msg4a db ‘xxh, return code=‘ msg4b db ‘xxh.’,cr,lf msg4_len equ $-msg4 _DATA ends _ENVIR segment para public ‘DATA’ ; example environment block to be passed to child db ‘PATH=‘,0 ; basic PATH, PROMPT, db ‘PROMPT=$p$_$n$g’,0 ; and COMSPEC strings db ‘COMSPEC=C:\COMMAND.COM’,0 db 0 ; extra null terminates block _ENVIR ends _STACK segment para stack ‘STACK’ db stksize dup (?) _STACK ends end main File CHILD.ASM È un semplice processo caricato da PARENT. stdin equ 0 ; standard input stdout equ 1 ; standard output stderr equ 2 ; standard error cr equ 0dh ; ASCII carriage return lf equ 0ah ; ASCII linefeed DGROUP group _DATA,STACK _TEXT segment byte public ‘CODE’ assume cs:_TEXT,ds:_DATA,ss:STACK MS-DOS um 38 di 138 main proc far mov ax,_DATA mov ds,ax mov dx,offset msg ; DS:DX = address of message mov cx,msg_len ; CX = length of message mov bx,stdout ; BX = standard output handle mov ah,40h ; AH = fxn 40H, write file/device int 21h ; transfer to MS-DOS jc main2 ; jump if any error mov ax,4c00h ; no error, terminate child int 21h ; with return code = 0 main2: mov ax,4c01h ; error, terminate child int 21h ; with return code = 1 main endp _TEXT ends _DATA segment para public ‘DATA’ msg db cr,lf,’Child executing!’,cr,lf msg_len equ $-msg _DATA ends STACK segment para stack ‘STACK’ dw 64 dup (?) STACK ends end main File ROOT.ASM Usa l’EXEC per caricare ed eseguire un overlays di nome OVERLAY. stdin equ 0 ; standard input stdout equ 1 ; standard output stderr equ 2 ; standard error stksize equ 128 ; size of stack cr equ 0dh ; ASCII carriage return lf equ 0ah ; ASCII linefeed DGROUP group _DATA,_STACK _TEXT segment byte public ‘CODE’ ; executable code segment assume cs:_TEXT,ds:_DATA,ss:_STACK stk_seg dw ? ; original SS contents stk_ptr dw ? ; original SP contents main proc far ; entry point from MS-DOS mov ax,_DATA ; set DS = our data segment mov ds,ax ; now give back extra memory mov ax,es ; AX = segment of PSP base mov bx,ss ; BX = segment of stack base sub bx,ax ; reserve seg stack - seg psp add bx,stksize/16 ; plus paragraphs of stack MS-DOS um 39 di 138 mov ah,4ah ; fxn 4AH = modify memory block int 21h ; transfer to MS-DOS jc main1 ; jump if resize failed display message ‘Root ‘segment executing...’ mov dx,offset DGROUP:msg1 ; DS:DX = address of message mov cx,msg1_len ; CX = length of message call pmsg ; allocate memory for overlay mov bx,1000h ; get 64 KB (4096 paragraphs) mov ah,48h ; fxn 48h, allocate mem block int 21h ; transfer to MS-DOS jc main2 ; jump if allocation failed mov pars,ax ; set load address for overlay mov pars+2,ax ; set relocation segment for overlay mov word ptr entry+2,ax ; set segment of entry point push ds ; save root’s data segment mov stk_seg,ss ; save root’s stack pointer mov stk_ptr,sp ; now use EXEC to load overlay mov ax,ds ; set ES = DS mov es,ax mov dx,offset DGROUP:oname ; DS:DX = overlay pathname mov bx,offset DGROUP:pars ; EX:BX = parameter block mov ax,4b03h ; function 4BH, subfunction 03H int 21h ; transfer to MS-DOS cli ; (for bug in some early 8088s) mov ss,stk_seg ; restore root’s stack pointer mov sp,stk_ptr sti ; (for bug in some early 8088s) pop ds ; restore DS = our data segment jc main3 ; jump if EXEC failed otherwise EXEC succeeded... push ds ; save our data segment call dword ptr entry ; now call the overlay pop ds ; restore our data segment display message that root segment regained control... mov dx,offset DGROUP:msg5 ; DS:DX = address of message mov cx,msg5_len ; CX = length of message call pmsg ; display it mov ax,4c00h ; no error, terminate program int 21h ; with return code = 0 main1: mov bx,offset DGROUP:msg2a ; convert error code call b2hex mov dx,offset DGROUP:msg2 ; display message ‘Memory mov cx,msg2_len ; resize failed...’ call pmsg jmp main4 main2: mov bx,offset DGROUP:msg3a ; convert error code call b2hex mov dx,offset DGROUP:msg3 ; display message ‘Memory mov cx,msg3_len ; allocation failed...’ call pmsg jmp main4 main3: mov bx,offset DGROUP:msg4a ; convert error code call b2hex mov dx,offset DGROUP:msg4 ; display message ‘EXEC mov cx,msg4_len ; call failed...’ call pmsg MS-DOS um 40 di 138 main4: mov ax,4c01h int 21h main endp b2hex proc near value push ax shr al,1 shr al,1 shr al,1 shr al,1 call ascii mov [bx],al pop ax and al,0fh call ascii mov [bx+1],al ret b2hex endp ascii proc near add al,’0’ cmp al,’9’ jle ascii2 add al,’A’-’9’-1 ascii2: ret ascii endp pmsg proc near DS:DX = address, ; error, terminate program ; with return code = 1 ; end of main procedure ; convert byte to hex ASCII call with AL = binary ; BX = addr to store string ; become first ASCII character ; store it ; isolate lower 4 bits, which ; become the second ASCII character ; store it ; convert value 00-0FH in AL ; into a “hex ASCII” character ; jump if in range 00-09H, ; offset it to range 0A-0FH, ; return ASCII char. in AL. ; displays message on standard output call with ; CX = length ; BX = standard output handle ; function 40H = write file/device ; transfer to MS-DOS ; back to caller mov bx,stdout mov ah,40h int 21h ret pmsg endp _TEXT ends _DATA segment para public ‘DATA’ ; static & variable data segment oname db ‘OVERLAY.OVL’,0 ; pathname of overlay file pars dw 0 ; load address (segment) for file dw 0 ; relocation (segment) for file entry dd 0 ; entry point for overlay msg1 db cr,lf,’Root segment executing!’,cr,lf msg1_len equ $-msg1 msg2 db cr,lf,’Memory resize failed, error code=‘ msg2a db ‘xxh.’,cr,lf msg2_len equ $-msg2 msg3 db cr,lf,’Memory allocation failed, error code=‘ msg3a db ‘xxh.’,cr,lf msg3_len equ $-msg3 msg4 db cr,lf,’EXEC call failed, error code=‘ msg4a db ‘xxh.’,cr,lf msg4_len equ $-msg4 msg5 db cr,lf,’Root segment regained control!’,cr,lf msg5_len equ $-msg5 _DATA ends _STACK segment para stack ‘STACK’ MS-DOS um 41 di 138 db stksize dup (?) _STACK ends end main ; defines program entry point File OVERLAY.ASM Caricata da ROOT, non usa lo stack perché usa quello di ROOT. stdin equ 0 ; standard input stdout equ 1 ; standard output stderr equ 2 ; standard error cr equ 0dh ; ASCII carriage return lf equ 0ah ; ASCII linefeed _TEXT segment byte public ‘CODE’ assume cs:_TEXT,ds:_DATA ovlay proc far ; entry point from root segment mov ax,_DATA ; set DS = local data segment mov ds,ax ; display overlay message ... mov dx,offset msg ; DS:DX = address of message mov cx,msg_len ; CX = length of message mov bx,stdout ; BX = standard output handle mov ah,40h ; AH = fxn 40H, write file/device int 21h ; transfer to MS-DOS ret ; return to root segment ovlay endp _TEXT ends _DATA segment para public ‘DATA’ msg db cr,lf,’Overlay executing!’,cr,lf msg_len equ $-msg _DATA ends end File EXECSORT.ASM Usa l’EXEC per eseguire il filtro MS-DOS SORT come un child process. stdin equ 0 ; standard input stdout equ 1 ; standard output stderr equ 2 ; standard error stksize equ 128 ; size of stack cr equ 0dh ; ASCII carriage return lf equ 0ah ; ASCII linefeed jerr macro target ; Macro to test carry flag local notset ; and jump if flag set. jnc notset ; Uses JMP DISP16 to avoid jmp target ; branch out of range errors notset: endm DGROUP group _DATA,_STACK ; ‘automatic data group’ _TEXT segment byte public ‘CODE’ ; executable code segment assume cs:_TEXT,ds:DGROUP,ss:_STACK stk_seg dw ? ; original SS contents stk_ptr dw ? ; original SP contents main proc far ; entry point from MS-DOS mov ax,DGROUP ; set DS = our data segment mov ds,ax MS-DOS um 42 di 138 mov ax,es mov bx,ss sub bx,ax add bx,stksize/16 mov ah,4ah int 21h jerr main1 mov bx,stdin mov ah,45h int 21h jerr main1 mov oldin,ax mov dx,offset DGROUP:infile mov ax,3d00h int 21h jerr main1 mov bx,ax mov cx,stdin mov ah,46h int 21h jerr main1 mov bx,stdout mov ah,45h int 21h jerr main1 mov oldout,ax mov dx,offset dGROUP:outfile mov cx,0 mov ah,3ch int 21h jerr main1 mov bx,ax mov cx,stdout mov ah,46h int 21h jerr main1 push ds mov stk_seg,ss mov stk_ptr,sp mov ax,ds mov es,ax mov dx,offset DGROUP:cname mov bx,offset DGROUP:pars mov ax,4b00h int 21h cli mov ss,stk_seg mov sp,stk_ptr sti pop ds jerr main1 mov bx,oldin mov cx,stdin mov ah,46h MS-DOS ; let AX = segment of PSP base ; and BX = segment of stack base ; reserve seg stack - seg psp ; plus paragraphs of stack ; fxn 4AH = modify memory block ; transfer to MS-DOS ; dup the handle for stdin ; transfer to MS-DOS ; jump if dup failed ; save dup’d handle ; now open the input file ; mode = read-only ; transfer to MS-DOS ; jump if open failed ; force stdin handle to ; track the input file handle ; transfer to MS-DOS ; jump if force dup failed ; dup the handle for stdout ; transfer to MS-DOS ; jump if dup failed ; save dup’d handle ; now create the output file ; normal attribute ; transfer to MS-DOS ; jump if create failed ; force stdout handle to ; track the output file handle ; transfer to MS-DOS ; save EXECSORT’s data segment ; save EXECSORT’s stack pointer ; set ES = DS ; DS:DX = child pathname ; EX:BX = parameter block ; function 4BH, subfunction 00H ; transfer to MS-DOS ; (for bug in some early 8088s) ; restore execsort’s stack pointer ; (for bug in some early 8088s) ; restore DS = our data segment ; jump if EXEC failed ; restore original meaning of ; standard input handle for ; this process um 43 di 138 int 21h jerr main1 ; jump if force dup failed mov bx,oldout ; restore original meaning mov cx,stdout ; of standard output handle mov ah,46h ; for this process int 21h jerr main1 ; jump if force dup failed mov bx,oldin ; close dup’d handle of mov ah,3eh ; original stdin int 21h ; transfer to MS-DOS jerr main1 ; jump if close failed mov bx,oldout ; close dup’d handle of mov ah,3eh ; original stdout int 21h ; transfer to MS-DOS jerr main1 ; jump if close failed display success message mov dx,offset DGROUP:msg1 ; address of message mov cx,msg1_len ; message length mov bx,stdout ; handle for standard output mov ah,40h ; fxn 40H = write file or device int 21h ; transfer to MS-DOS jerr main1 mov ax,4c00h ; no error, terminate program int 21h ; with return code = 0 main1: mov ax,4c01h ; error, terminate program int 21h ; with return code = 1 main endp ; end of main procedure _TEXT ends _DATA segment para public ‘DATA’ ; static & variable data segment infile db ‘MYFILE.DAT’,0 ; input file for SORT filter outfile db ‘MYFILE.SRT’,0 ; output file for SORT filter oldin dw ? ; dup of old stdin handle oldout dw ? ; dup of old stdout handle cname db ‘SORT.EXE’,0 ; pathname of child SORT process pars dw 0 ; segment of environment block (0 = inherit parent’s) dd tail ; long address, command tail dd -1 ; long address, default FCB #1 (-1 = none supplied) dd -1 ; long address, default FCB #2 (-1 = none supplied) tail db 0,cr ; empty command tail for child msg1 db cr,lf,’SORT was executed as child.’,cr,lf msg1_len equ $-msg1 _DATA ends _STACK segment para stack ‘STACK’ db stksize dup (?) _STACK ends end main ; defines program entry point Quest’applicazione richiede i file SORT.EXE e MYFILE.DAT nella directory corrente e manda in uscita MYFILE.SRT. MS-DOS um 44 di 138 TSR (TERMINATE AND STAY RESIDENT) Introduzione Ad una prima occhiata, avere un processo morto in giro che non può essere attivato non sembra un’attrattiva interessante; è, però da ricordare che i processi in MS-DOS possono installare i loro driver d’interrupt. In particolare, un processo può installare un driver di una nuova tastiera che è chiamato per ogni interruzione di tastiera che sul PC si ha quando è premuto o rilasciato qualsiasi tasto, compreso CTRL, ALT e SHIFT. Questo driver può essere allocato all’interno del processo inaccessibile TSR. Il driver esamina velocemente il tasto per vedere se esso è un tasto speciale o una combinazione di tasti, chiamata hot key, che attiva il codice TSR. In caso contrario, il carattere è messo nella coda d’input di caratteri del SO e il TSR ritorna dall’interruzione all’applicazione. Se è una hot key, il TSR inizia a lavorare e fare ciò che era stato programmato. Scrivere un TSR è complicato e devono essere risolti molti problemi. Prima di tutto il TSR deve copiare l’immagine del video attuale e salvarla da un’altra parte, così essa può essere recuperata quando il TSR termina il suo lavoro. Esso deve inoltre eseguire il suo lavoro senza chiamare MS-DOS poiché questi dovrebbe essere stato attivo al momento dell’interruzione. MS-DOS non è rientrante, il che significa che non può gestire una seconda chiamata finché non è terminata la prima. Tra le altre cose, il TSR non può usare MS-DOS per leggere la tastiera per gli input successivi e non può usarlo per scrivere sul video e per accedere ai file. Esso, inoltre, non può usare il BIOS perché anche questo dovrà trovarsi nel mezzo di una chiamata al momento della battuta. Ne consegue che il TSR deve avere un proprio I/O o trovare dei buoni sotterfugi per raggirare MS-DOS in modo che pensi che esso sia l’applicazione attualmente in esecuzione, manipolando le strutture dei dati interni di MS-DOS. L’applicazione DOSKEY è un TSR che è fornito standard con MS-DOS. MS-DOS contiene alcuni accorgimenti che rendono possibile ai TSR fare chiamate di sistema raggirando MS-DOS; nessuna di queste è documentata ufficialmente nel manuale Microsoft, il Microsoft MS-DOS Programmer’s Reference Manual. La Microsoft mette in guardia i programmatori dall’usare chiamate di sistema non documentate perché si riserva di modificarle o eliminarle nelle versioni future. Al contrario, le chiamate di sistema ufficiali non sono rimosse quasi mai e non ha importanza quanto esse siano obsolete. Le applicazioni residenti sono, come indica il nome, collocate permanentemente in memoria e in seguito eseguite solo su richiamo esplicito da parte di un’altra applicazione, per un tasto premuto dall’operatore o per mezzo di un interrupt. Un esempio di TSR è la parte principale di COMMAND.COM, che una volta caricata resta in memoria e i cui moduli sono richiamati con interruzioni S/W. Altro esempio è dato dalla routine di stampa, PRINT.COM, al primo richiamo PRINT s’installa in memoria e quindi vi rimane, pronta ad entrare in funzione quando richiesto. In MS-DOS è generato un tick di sistema con una frequenza di 18.2065 volte al secondo, questo tick è utilizzato per comandare il processo di stampa che quindi appare funzionante parallelamente ad un qualsiasi altro processo in esecuzione. MS-DOS um 45 di 138 Al termine di questa procedura di sistema è chiamato il processo il cui indirizzo corrisponde all’INT 1CH normalmente il vettore relativo ad 1CH punta ad IRET. Se però questo vettore è ridefinito, si ha modo di fare eseguire automaticamente un’applicazione programma 18.2065 volte al secondo. L’intercettazione del tick di sistema è la chiave per il funzionamento del multitasking. In MS-DOS è possibile scrivere proprie routine da rendere residenti e associarle ad interrupt particolari, questa tecnica d’intercettazione rappresenta un mezzo molto potente nello sviluppo di applicazioni e sistemi. È, infatti, possibile intercettare qualsiasi interrupt, anche quelli generati automaticamente in situazione di errore per esempio: division by zero, oppure chiamate in casi particolari, quali l’immissione da tastiera di caratteri CTRL+ C e CTRL+BREAK. FUNZIONE 31H Descrizione Categoria Input Output TERMINATE AND STAY RESIDENT (KEEP PROCESS) Applicazioni residenti. Servizi di sistema. DX = numero di paragrafi del TSR. AL = codice di uscita. FUNZIONE 25H Descrizione Categoria Input SET INTERRUPT VECTOR Inizializza un vettore d’interrupt. Servizi di sistema. AH = 25H AL = numero d’interrupt da 0 a FFH. DS:DX = pointer alla routine d’interrupt (DS = CS, DX = IP). Si consiglia di leggere e salvare il vecchio vettore prima di aggiornarlo, con la funzione 35H, in modo da poterlo ripristinare una volta terminata l’applicazione. Esempio per applicazioni COM, non è necessario inizializzare DS perché coincide con CS. MOV AH,25H MOV AL,80H MOV DX,OFFSET serv_80h INT 21H serv_80h PROC NEAR .... serv_80h ENDP Esempio per applicazioni EXE, si deve inizializzare DS con il valore di segmento nel quale risiede la routine. PUSH DS MOV AH,25H MOV AL,80H MOV DX,SEG serv_80h MOV DS,DX MOV DX,OFFSET serv_80h INT 21H POP DS serv_80h PROC NEAR .... serv_80h ENDP MS-DOS um 46 di 138 FUNZIONE 35H Descrizione Categoria Input Output GET INTERRUPT VECTOR Legge un vettore di interrupt. Servizi di sistema. AH = 35H AL = numero d’interrupt da 0 a FFH. ES:BX = pointer al vettore d’interrupt (ES = CS, BX = IP). Il metodo più pratico per accedere dall’esterno ad un processo residente è per mezzo di un interrupt S/W. Per questo occorre che l’indirizzo del punto di entrata del processo sia scritto nella tabella degli interrupt collocata nella parte più bassa della memoria. File RTCLOCK.ASM Mantiene un orologio interno il cui valore è mostrato in continuazione nella parte superiore dello schermo nella forma HH:MM:SS e non influisce sull’esecuzione di altri processi attivi al momento. Il tick di sistema è uguale a 1/18.2065 è aggiornato 18.2065 volte al secondo, alla mezzanotte il tick è posto a zero e il conteggio ricomincia. Il tick è letto da INT 1AH funzione 00H e messo in CX:DX. 1 giorno 18.2065 * 60 * 60 * 24 = 1573041.6 tick. 1 ora 18.2065 * 60 * 60 = 65543.4 tick. 1 minuto 18.2065 * 60 = 1092.4 tick. Ora corrente = tick correnti / 65543.4. resto1 = numero di tick in più rispetto l’ora corrente. minuti correnti = resto1 / 1092.34. resto2 = numero di tick in più rispetto ai minuti correnti. secondi correnti = resto2 / 18.2065. 65545 non è rappresentabile in una word per cui non si può usare DIV, basta dividere per due il numero di tick correnti, per esempio 32772.7 Si divide in due parti, una d’inizializzazione e una residente. Initialize è eseguita una sola volta, al primo richiamo di RTCLOCK. In questa parte si ricorre a MS-DOS per associare resident_clock all’interruzione 1CH e per terminare subito l’esecuzione, lasciando però il codice residente in memoria, 40 paragrafi sono sufficienti a contenere l’intero processo. resident_clock deve salvare su stack che appartiene al processo originale interrotto, lo stato dei registri di cui fa uso e ripristinarli al termine dell’esecuzione. Non è necessario salvare AX, DX e DS in quanto i loro valori sono già stati messi su stack dalla routine originale MS-DOS di gestione tick di sistema. Lo stato corrente della variabile time di sistema è ottenuto con un richiamo al BIOS INT 1AH Times Of Day, questa variabile è contenuta in macchina come il numero di tick trascorsi da mezzanotte. Questo valore può eccedere i 16 bit di lunghezza, per cui la parte alta di time è ritornata in CX e la parte meno significativa in DX. RTCLOCK deve estrarre da time i valori attuali di ore, minuti e secondi e convertirli in caratteri ASCII, formattandoli nella stringa outstr da mostrare sullo schermo direttamente nella RAM video in quanto permette un trasferimento molto rapido. La posizione esatta di quest’area dipende dal tipo di scheda grafica, nell’applicazione essa è definita con la costante vidseg. Le caratteristiche principali alle quali devono rispondere i moduli di servizio degli interrupt sono, infatti, compattezza e rapidità di esecuzione. Una volta completate queste operazioni, il controllo torna alla procedura originale con il ripristino dallo stack dei valori dei registri e l’istruzione IRET. MS-DOS um 47 di 138 STACKSEG SEGMENT PARA STACK ‘STACK’ DB 200H DUP (?) STACKSEG ENDS VIDSEG EQU 0B800H ;0B00H per video monocromatici OUT_MODE EQU 112 ;normale = 7 alta intensità = 15 reverse = 112 BYTE_TO_DEC MACRO ;conversione di un byte con valore 0..99 contenuto in AL XOR AH,AH ;nei char ASCII corrispondenti in AH e AL MOV BL,10 ;AL modulo 10 DIV BL ;quoziente in AL resto in AH ADD AX,3030H ;conversione in ASCII ENDM DATA SEGMENT WORD ‘DATA’ TIME DB 16 DUP (OUT_MODE) ;stringa uscita schermo HOURS DB 0 MINUTES DB 0 DATA ENDS CSEG SEGMENT WORD ‘CSEG’ ASSUME CS:CSEG,DS:DATA RESIDENT_CLOCK: ;sezione residente in memoria CLI PUSH BX PUSH CX PUSH SI PUSH DI PUSH ES STI MOV AX,DATA MOV DS,AX MOV AH,0H ;servizio bios time of day INT 1AH ;richiamo funzione bios, il risultato (numero tick) in CX:DX MOV AX,DX ;la parte bassa va in AX MOV DX,CX ;la parte alta va in DX SHR DX,1 DX / 2 SHR AX,1 ;AX / 2 AND CL,00000001B ;se c’è riporto nella parte alta trasporto in AX CMP CL,0 JE CONT_1 ADD AH,10000000B CONT_1: MOV CX,32772 ;65543 tick / ora approssimato da 2 * 32772 DIV CX CMP AX,24 ;DX:AX / CX risultato in AX JB CONT_2 ;azzeramento se ore>=24 XOR AX,AX CONT_2: MOV HOURS,AL MOV AX,DX ;resto della prima divisione XOR DX,DX MOV CX,546 ;1092 conteggi / minuto approssimato da 2 * 546 DIV CX CMP AX,60 ;DX:AX / CX risultato in AX JB CONT_3 ;azzeramento se minuti >=60 XOR AX,AX MS-DOS um 48 di 138 CONT_3: MOV MINUTES,AL MOV AX,DX ;resto della seconda divisione XOR DX,DX MOV CX,10 ;18.2 conteggi / secondo approssimato da 91 * 2 / 10 MUL CX ;AX * CX risultato in DX:AX MOV CX,91 DIV CX ;DX:AX / CX risultato in AX CMP AX,60 JB CONT_4 ;azzeramento se secondi >=60 XOR AX,AX CONT_4: BYTE_TO_DEC ;conversione di secondi, minuti e ore in ASCII MOV TIME[12],AL MOV TIME[14],AH MOV AL,MINUTES BYTE_TO_DEC MOV TIME[6],AL MOV TIME[8],AH MOV AL,HOURS BYTE_TO_DEC MOV TIME[0],AL MOV TIME[2],AH MOV TIME[4],”:” MOV TIME[10],”:” CLD MOV SI,OFFSET TIME ;DS:DX punta a TIME MOV BX,VIDSEG MOV ES,BX MOV DI,8CH ;ES:DI punta a destinazione nella memoria video MOV CX,16 ;16 byte da copiare REP MOVSB ;copia nella memoria video CLI POP ES POP DI POP SI POP CX POP BX STI IRET ;uscita da RTCLOCK, termine parte residente INITIALIZE: ;parte non residente eseguita una sola volta ASSUME DS:CSEG MOV AX,CSEG MOV DS,AX ;DS:DX punta resident_clock MOV DX,OFFSET RESIDENT_CLOCK MOV AL,1CH MOV AH,25H INT 21H MOV DX,40 ;DX = numero paragrafi residenti 40 * 16 = 640 byte MOV AL,0 ;codice di uscita processo MOV AH,31H INT 21H CSEG ENDS END INITIALIZE MS-DOS um 49 di 138 Un altro tipo di TSR orologio residente, la parte transiente ha i seguenti compiti. Salva in A = SEG:OFF il vettore d’interrupt corrente da intercettare; modifica il vettore d’interrupt in modo che punti alla prima istruzione della parte residente; termina informando MS-DOS che deve essere liberata solo la parte di memoria occupata dalla parte transiente. La parte residente rimane in memoria mentre le altre applicazioni sono in esecuzione e deve effettuare le seguenti operazioni: salva nello stack lo stato del sistema; esegue il processo; ripristina dallo stack lo stato del sistema; salta all’indirizzo contenuto in A. div_ore EQU 32772 div_min EQU 546 div_sec EQU 91 dati SEGMENT buf_video DW ? porta_stato DW ? vecchio_vettore DD ? colonna DW 0000h dati ENDS codice SEGMENT ASSUME CS:codice,DS:dati conv PROC NEAR MOV CL,10 DIV CL ADD AX,3030h RET conv ENDP visualizza PROC NEAR PUSHF PUSH DX MOV DX,porta_stato PUSH AX CLI CLD ciclo_1:IN AL,DX TEST AL,1 JNZ ciclo_1 ciclo_2:IN AL,DX TEST AL,1 JZ ciclo_2 POP AX MOV AH,1Eh STOSW POP DX POPF RET visualizza ENDP parte_res: PUSH CX PUSH DI PUSH ES MOV AX,dati MOV DS,AX MOV AX,buf_video MOV ES,AX MS-DOS ;32772 * 2 = 65544 = 60 * 60 * 18.2065 ;546 * 2 = 1092 = 60 * 18.2065 ;91 * 2 = 182 cioè circa 18.2065 * 10 ;converte un numero minore ;di 100 in AX nei due caratteri ;ASCII corrispondenti in AL e AH ;salva anche DX nello stack ;e carica porta_stato in DX ;sfondo blu e carattere giallo ;ripristina DX ;Salva CX, DI ed ES ;AX, DX e DS sono già stati ;salvati dal SO ;carica in AX il segmento dati ;e lo sposta in DS ;carica buf_video in AX ;e lo sposta in ES um 50 di 138 MOV DI,colonna MOV AL,’ ‘ CALL visualizza MOV AH,0 INT 1Ah SHR DX,1 SHR CX,1 JNC L_0 OR DX,8000h L_0: XCHG DX,CX MOV AX,CX MOV CX,div_ore DIV CX CMP AX,24 JNE L_1 XOR AX,AX L_1: CALL conv MOV CH,AH CALL visualizza MOV AL,CH CALL visualizza MOV AL,’:’ CALL visualizza XOR AX,AX XCHG AX,DX MOV CX,div_min DIV CX CMP AX,60 JNE L_2 XOR AX,AX L_2: CALL conv MOV CH,AH CALL visualizza MOV AL,CH CALL visualizza MOV AL,’:’ CALL visualizza MOV AX,DX XOR DX,DX MOV CX,10 MUL CX MOV CX,div_sec DIV CX CMP AX,60 JNE L_3 XOR AX,AX L_3: CALL conv MOV CH,AH CALL visualizza MOV AL,CH CALL visualizza MOV AL,’ ‘ CALL visualizza POP ES MS-DOS ;carica la colonna di inizio in DI ;in AL uno spazio ;e visualizza a partire da colonna ;carica 0 in AH e richiama il BIOS ;per la lettura del contatore dei tick di sistema ;dividi per due DX ;e CX ;se il bit meno significativo di CX è a 0 salta a L_0 altrimenti ;metti ad 1 il bit più significativo di DX ;scambia DX con CX e sposta CX in AX ;ora i tick di sistema si trovano nella coppia DX:AX ;carica 32772 in CX ;e dividi ;confronta con 24 ;se non uguale salta altrimenti ;considera zero il quoziente ;chiama la procedura di conversione ;sposta temporaneamente AH in CH ;e visualizza prima cifra ore ;recupera CH e visualizza ;seconda cifra ore ;visualizza il ;carattere “:” ;azzera AX ;sposta il resto in AX e 0 in DX ;carica 546 in CX ;e dividi per CX ;confronta con 60 ;se non uguale salta altrimenti ;considera 0 il quoziente ;chiama la procedura di conversione ;salva temporaneamente AH in CH ;visualizza prima cifra minuti ;recupera CH e visualizza ;seconda cifra minuti ;visualizza il ;carattere “:” ;sposta il resto in AX ;azzera DX ;carica 10 in CX ;e moltiplica ;carica 91 in CX ;e dividi per CX ;confronta con 60 ;se non uguale salta altrimenti ;considera 0 il quoziente ;chiama la procedura di conversione ;salva temporaneamente AH in CH ;e visualizza prima cifra secondi ;recupera CH ;e visualizza seconda cifra ;visualizza uno ;spazio ;ripristina i um 51 di 138 POP DI ;registri ES POP CX ;DI e CX e JMP vecchio_vettore ;salta all’indirizzo contenuto in vecchio_vettore parte_trans PROC NEAR MOV AX,dati ;carica il segmento dati in AX MOV DS,AX ;e lo sposta in DS CALL det_porta_stato ;chiama la procedura che determina l’indirizzo della porta di stato del CRT controller MOV porta_stato,DX ;e lo salva in porta_stato CALL det_buf_video ;routine che determina l’indirizzo del buffer video MOV buf_video,DX ;e lo salva in buf_video SUB colonna,10 ;sottrae 10 (spazio utilizzato per stampare l’ora) a colonna SHL colonna,1 ;e moltiplica per due (infatti ogni carattere è rappresentato nel buffer video con due byte ; uno di codice ed uno per l’attributo) MOV AL,1Ch ;legge il vettore corrente MOV AH,35h ;dell’interrupt 1CH e lo salva INT 21h ;in vecchio_vettore MOV WORD PTR vecchio_vettore,BX MOV WORD PTR vecchio_vettore+2,ES MOV AX,codice ;carica segmento codice in AX MOV DS,AX ;e lo sposta in DS MOV DX,OFFSET parte_res ;offset di parte_res in DX MOV AL,1Ch ;modifica il vettore 1Ch in MOV AH,25h ;modo che punti a parte_res INT 21h MOV DX,30 ;carica in DX il numero di paragrafi necessari alla parte ;residente (480 byte) ;parte_res = PSP (256 byte) + dati + occupazione MOV AL,0 ;carica in AL il codice di terminazione MOV AH,31h ;carica 31h in AH INT 21h ;e termina rimanendo residente parte_trans ENDP det_buf_video PROC NEAR PUSH BX PUSH AX MOV AH,0Fh INT 10h MOV BYTE PTR colonna,AH ;salva AH (numero di caratteri per riga) nella variabile colonna MOV DX,128 CMP AH,40 JE no80 SHL DX,1 no80:XCHG DX,AX MUL BH CMP DL,06 JG mono ADD AX,0800h mono:ADD AX,0B000h MOV DX,AX POP AX POP BX RET MS-DOS um 52 di 138 det_buf_video ENDP det_porta_stato PROC NEAR PUSH DS XOR DX,DX MOV DS,DX MOV DX,WORD PTR DS:[0463h] ADD DX,6 POP DS RET det_porta_stato ENDP codice ENDS END parte_trans TSRInt EQU 64H STDOUT EQU 1 RESIDENT_DATA SEGMENT word public ‘DATA’ Message DB 0Dh,0Ah,’Hello, World’,0Dh,0Ah RESIDENT_DATA ENDS RESIDENT_TEXT SEGMENT byte public ‘CODE’ ASSUME cs:RESIDENT_TEXT,ds:RESIDENT_DATA TSRAction PROC far sti push ds push ax push bx push cx push dx mov dx,seg RESIDENT_DATA mov ds,dx mov dx,offset Message mov cx,16 ;CX = length mov bx,STDOUT ;BX = file handle mov ah,40h int 21h pop dx pop cx pop bx pop ax pop ds iret TSRAction ENDP RESIDENT_TEXT ENDS TRANSIENT_STACK SEGMENT word stack ‘TSTACK’ DB 80h dup(?) TRANSIENT_STACK ENDS TRANSIENT_TEXT SEGMENT para public ‘TCODE’ ASSUME cs:TRANSIENT_TEXT,ss:TRANSIENT_STACK HelloTSR PROC far ; CS:IP -> SnapTSR, SS:SP -> stack, DS,ES -> PSP ; Install this TSR’s interrupt handler mov ax,seg RESIDENT_TEXT mov ds,ax mov dx,offset RESIDENT_TEXT:TSRAction mov al,TSRInt mov ah,25h MS-DOS um 53 di 138 int 21h ; Terminate and stay resident mov dx,cs ;DX = paragraph address of start of transient portion (end of resident portion) mov ax,es ;ES = PSP segment sub dx,ax ;DX = size of resident portion mov ax,3100h ;AH = INT 21h function number (TSR) AL = 00H (return code) int 21h HelloTSR ENDP TRANSIENT_TEXT ENDS END HelloTSR Bisogna eseguire INT 64H per visualizzare il messaggio seguente. #include <dos.h> int main (void) {union REGS reg; int86(0x64,®,®); return(0); } Perché I TSR SONO COSì PROBLEMATICI? Perché MS-DOS non è rientrante: in altre parole se il DOS sta operando con un’applicazione, non può sospendere tale operazione per eseguire qualcos’altro e ritornare poi al suo impiego iniziale. Affinché un TSR sappia di poter interrompere il processo DOS è necessario. 1. Esaminare un flag indicante la possibilità di effettuare l’interruzione. 2. Intercettare un interrupt, tutti i TSR sono attivati da un interrupt. Le routine di servizio degli interrupt ISR (Interrupt Service Routine) devono essere scritte come funzioni di tipo FAR, devono terminare con IRET, devono all’inizio inserire tutti i registri nello stack con PUSH, devono al termine recuperare tutti i registri con POP. Ad esempio INT 64H si utilizza quale flag indicante se il TSR è già stato caricato. BorlandC dispone, come supporto per i TSR, del modificatore del tipo di funzione denominato INTERRUPT che preserva tutti i registri e termina con IRET. Non far coesistere due o più TSR. Non bypassare mai MS-DOS e il BIOS. Definire una propria DTA (Data Transfer Area) per accedere ai dischi: il DOS trasferisce le informazioni nella DTA allocata per ogni applicazione, la DTA di default è parte del PSP di cui tutte le applicazioni dispongono, quando un TSR interrompe un’altra applicazione esso eredita il PSP dell’applicazione quindi se esso effettua un I/O corre il rischio di sovrascrivere le informazioni già presenti nella DTA dell’altra applicazione. BorlandC dispone di una var _psp. PROGETTO BASE DI UN TSR Tutti i TSR sono costituiti da tre parti principali. 1. INIZIALIZZAZIONE DEL TSR Inizializza ogni cosa in base alle esigenze dell’applicazione. Reindirizzamento dei vettori di interrupt usati. Chiamata alla funzione DOS 0x31 in BorlandC è la funzione seguente. void keep (unsigned char status,unsigned mem_size); MS-DOS um 54 di 138 Dove. mem_size è un valore a 16 bit che indica la quantità di RAM da allocare per il TSR: operazione complessa. 2. ISR Per intercettare la pressione di un tasto si dovrà sostituire INT 9H con uno appositamente creato: è importante ricordarsi di memorizzare l’indirizzo della routine ISR associata a tale interrupt. A questo punto, ogni volta che sarà premuto un tasto, si avrà la generazione di un INT 9H, fatto che si tradurrà in una chiamata alla nuova ISR di tastiera. La nuova ISR dovrà chiamare la routine originale di ISR e poi determinare se il tasto premuto corrisponde al tasto chiave: se il TSR dovrà essere attivato solo se la situazione corrente lo consente. Inoltre il tasto chiave dovrà essere eliminato dalla coda d’input, in modo tale che lo stesso non sia poi preso in considerazione dall’applicazione interrotta. Il TSR dovrà disporre anche di un’altra routine ISR per determinare se la operazione corrente del DOS può essere interrotta. 3. L’APPLICAZIONE Il TSR deve operare attraverso una finestra perché così l’utente può continuare a vedere parte dell’applicazione interrotta. Inoltre, la quantità di RAM e il tempo richiesto per memorizzare e ripristinare lo schermo è minore. TSR E MODI GRAFICI È possibile usare un TSR in modo grafico, però è opportuno attendere la modalità testo per questi motivi. 1. Ci sono pochi modi testo 80X25 colori, bianco e nero, monocromatico mentre vi sono molti modi grafici. 2. In modo testo 80X25 servono 4000 byte per memorizzare lo schermo. 3. Tutti i modi grafici richiedono più memoria: almeno 64 KB. QUANDO PUò ESSERE EFFETTUATA L’INTERRUZIONE Un’operazione DOS può essere interrotta quando non sta facendo nulla, al contrario non si deve interrompere il DOS mentre sta effettuando un accesso al disco o durante la scrittura sullo schermo. Ma esaminando PRINT si sono trovate due funzioni. 1. L’interrupt di attesa evento DOS. Quando il DOS attende l’input dall’utente, entra in un loop nel quale è controllata la pressione di un tasto. Parte di questo loop consiste nell’esecuzione di INT 28H chiamato dalle 12 funzione DOS d’I/O carattere. Ogni volta che INT 28H è eseguito il DOS può essere interrotto. L’applicazione dovrebbe intercettare INT 28H e usarlo per richiamare il TSR solo se il tasto chiave è stato premuto. Il problema però è che il DOS usa INT 28H solo per funzioni d’I/O carattere, quindi è necessario un altro meccanismo che consenta di controllare con maggior frequenza la chiamata al TSR, molte applicazioni non chiamano mai l’INT 28H. 2. Il flag di DOS attivo. Durante la fase di attività del DOS vi è un byte che è messo a 1, mentre è a 0 se è inattivo. La locazione di questo flag può essere gestita con la chiamata a INT 34H che restituisce il segmento del flag in ES e l’offset in BX. Prima di essere attivato, l’applicazione dovrà assicurarsi che tale flag sia a 0, altrimenti il MS-DOS um 55 di 138 TSR dovrà rimanere inattivo. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <dos.h> #include <ctype.h> #include <fcntl.h> #include <conio.h> #include <bios.h> #include <io.h> #define BORDER 1 #define MAX_FRAME 3 #define REV_VID 0x70 #define NORM_VID 7 #define VID_SIZE 4000 #define STK_SIZE 0x2000 /* prototipi di funzione della finestra */ void save_video(int num), restore_video(int num); void write_string(int x, int y, char *p, int attrib); void write_char(int x, int y, char ch, int attrib); void tsrdisplay_header(int num), tsrdraw_border(int num); void tsrwindow_gets(int num , char *s); void tsrwindow_cleol(int num), tsrwindow(int num); void tsrwindow_cls(int num), set_vid_mem(void); void tsrdeactive(int num),tsrwindow_bksp(int num),goto_xy(int x, int y); int make_tsrwindow(int num, char *header, int startx, int starty, int endx, int endy, int border); int tsrwindow_xy(int num, int x, int y),tsrwindow_puts(int num, char *str); int video_mode(void), tsrwindow_putchar(int num, char ch); int tsrwindow_getche(int num); int tsrwindow_upline(int num), tsrwindow_downline(int num),readkey(void); /* prototipi di funzione del TSR */ void cursor_pos(void),activate_tsr(void); void interrupt tsr_keystroke(void); void interrupt dos_idle(void); void interrupt new_int8(void); void interrupt (*old_int28)(); void interrupt (*old_int8)(); void interrupt (*old_key)(); void interrupt (*old_int64)(); void notepad(void), calc(void),code(void); int push(int i), pop(void); char far *vid_mem;char video; struct window_frame { int startx, endx, starty, endy; /* angoli della finestra */ int curx, cury; /* posizione corrente del cursore nella finestra */ unsigned char *p; /* puntatore al buffer */ char *header; /* titolo della finestra */ int border; /* stato del bordo: presente/assente */ int active; /* stato della finestra: 1 se attiva, altrimenti 0 */ } frame[MAX_FRAME]; char wp[VID_SIZE]; /* buffer che sarà’ usato dalla funzione save_video() per MS-DOS um 56 di 138 memorizzare il contenuto dello schermo */ /* se l'applicazione è attiva allora busy è definita a 1, altrimenti a 0.*/ char busy = 0,far *dos_active; unsigned char stck[STK_SIZE]; unsigned int sp, ss; int old_row, old_col, key; int main(void) { union REGS r; struct SREGS s; clrscr(); /* verifica che il TSR non sia già stato caricato perchè esso userebbe nuove porzioni di RAM, se l'applicazione esce dopo aver rediretto i vettori d’interrupt ma prima di aver chiamato la function DOS 31H, avviene che ad ogni esecuzione di ridirezione salterà in posizioni sconosciute. */ old_int64 = getvect(0x64); /* interrupt non usato */ if(!old_int64) setvect(0x64, new_int8); /* attiva un flag */ else { printf("L'applicazione residente e’ gia’ stata caricata."); return (1); } /* ottiene l’indirizzo del flag dos_active */ r.h.ah = 0x34; int86x(0x21, &r, &r, &s); dos_active = MK_FP(s.es, r.x.bx); /* prende gli indirizzi della vecchia ISR e li memorizza */ old_key = getvect(9); /* interrupt di tastiera */ old_int28 = getvect(0x28); /* interrupt 28H */ old_int8 = getvect(8); /* interrupt di orologio */ /* reindirizza i vettori d’interrupt alle nuove routine, è importante collegare le nuove ISR a quelle originali perchè, come nel caso dell’interrupt da tastiera e di orologio, le routine ISR originali svolgono alcuni compiti cruciali */ setvect(9, tsr_keystroke); setvect(0x28, dos_idle); setvect(8, new_int8); printf("F1: Blocco Appunti F2: Calcolatore F3: Cripta file"); printf(" F4: Disattiva\n"); key = 0; /* passa i codici di tastiera alle funzioni */ set_vid_mem(); /* prende l’indirizzo della memoria video */ /* inizializza tutte le finestre */ make_tsrwindow(0, " Blocco appunti [Esc per uscire] ", 20, 5, 60, 16, BORDER); make_tsrwindow(1, " Calcolatore ", 20, 8, 60, 12, BORDER); make_tsrwindow(2, " Cripta file ", 20, 8, 60, 10, BORDER); keep(0, 2000); /* termina e rimane residente */ return (0); } /* questa è la funzione che intercetta l’interrupt di tastiera (INT 9H), richiama la ISR originale che legge il tasto e lo accoda nel buffer di tastiera e verifica se è stato premuto un tasto chiave, questa funzione non richiama nessuna function DOS o BIOS per leggere il tasto dal buffer, al contrario lo interroga direttamente per due motivi: - risulta più semplice controllare direttamente il buffer - consente la modifica diretta del buffer la function non effettua direttamente l’attivazione del TSR perché alcune MS-DOS um 57 di 138 applicazioni non possono essere interrotte durante l’interrupt da tastiera IL BUFFER DI TASTIERA il DOS prevede che il limite max per il buffer sia di 15 caratteri, ogni volta che è premuto un tasto è generato l’INT 9H, la function ISR per l’input da tastiera legge il carattere dalla porta e lo accoda nel buffer, quando è chiamata una function DOS o BIOS per l’input di un carattere dalla tastiera, solo il contenuto del buffer è esaminato e non la porta relativa: quindi anche le funzioni di un programmatore possono controllare direttamente il buffer di tastiera permettendo così al TSR di verificare l’eventuale pressione di un tasto chiave, il buffer di tastiera è situato all’indirizzo: 0000:041E, dato che ogni codice di scansione tastiera richiede 2 byte, la lunghezza richiesta per il buffer di 15 caratteri è pari a 30 byte, in realtà il buffer è lungo 32 byte a causa del fatto che in coda ad esso è inserito automaticamente un codice di CR, il buffer è strutturato a coda circolare con pointer d'inizio coda (0000:041A) che punta all’ultimo carattere inserito da tastiera e fine coda (0000:041C) che punta al carattere che sarà utilizzato alla prima richiesta di input del DOS o del BIOS */ void interrupt tsr_keystroke(void) { int far *t2 = (int far *) 1050; /* indirizzo puntatore di inizio coda */ char far *t = (char far *) 1050; /* indirizzo puntatore di inizio coda */ (*old_key)(); /* prima chiama la vecchia ISR */ if(*t != *(t+2)) { /* se non e’ vuoto */ t += *t-30+5; /* avanza alla posizione del carattere */ if(*t>=59 && *t<=62) { switch(*t) { /* controlla il codice di scansione */ /* la ragione per cui è utilizzata la codifica del tasto piuttosto che il suo codice di scansione è dovuta al fatto che per modificare il tasto chiave basta cambiare una sola linea di codice */ case 59: key = 1; /* F1 - blocco appunti */ break; case 60: key = 2; /* F2 - calcolatore */ break; case 61: key = 3; /* F3: cripta file */ break; case 62: key = 4; /* F4: disattiva il TSR */ break; *(t2+1) = *t2; } } } /* nuovo interrupt 8, controlla se il DOS è libero, cioè se busy=0 e se key=tasto chiave, se entrambe le condizioni sono vere allora il tsr è attivato. */ void interrupt new_int8(void) { (*old_int8)(); /* chiama l’interrupt 8 originale */ /* se il DOS è inattivo, il TSR non è stato ancora attivato e se è stato premuto un tasto chiave, allora attiva il TSR */ if(!*dos_active && !busy && key) activate_tsr(); } /* questa funzione intercetta l’INT 28H (evento di DOS in attesa), controlla se il DOS è libero, cioè se busy=0 e se key=tasto chiave, se entrambe le condizioni sono vere allora il TSR è attivato */ void interrupt dos_idle(void) { (*old_int28)(); /* chiama la ISR originale dell’interrupt 0x28 */ MS-DOS um 58 di 138 if(!busy && key) activate_tsr(); } /* richiama il TSR */ void activate_tsr(void) { /* definisce lo stack del TSR */ disable(); /* disabilita gli interrupt durante la sostituzione */ ss = _SS; sp = _SP; _SS = _DS; _SP = (unsigned) &stck[STK_SIZE-2]; enable(); /* abilita gli interrupt */ cursor_pos(); /* prende la posizione corrente del cursore */ /*controlla il modo video, non richiama nulla se non si trova in modo testo a 80 colonne */ video = video_mode(); if(!busy && (video==7 || video==3 || video==2)) { busy = !busy; /* non consente una seconda attivazione */ switch(key) { case 1: notepad(); break; case 2: calc(); break; case 3: code(); break; } busy = !busy; } if(key==4) /* disattiva il TSR */ write_string(old_col, old_row, "TSR disattivato.", NORM_VID); goto_xy(old_col, old_row); /* ripristina la posizione del cursore */ /* ripristina il vecchio stack */ disable(); _SP = sp; _SS = ss; enable(); if(key==4) { /* ripristina le ISR originali e libera la memoria */ setvect(8, old_int8); setvect(9, old_key); setvect(0x28, old_int28); setvect(0x64, old_int64); freemem(_psp); /* libera il blocco usato dall'applicazione */ } else key = 0; } /********************************************************************/ /* Funzioni di applicazione della finestra pop-up */ /* Calcolatore a quattro operatori basato sul sistema RPN */ /********************************************************************/ #define MAX 100 int *p; /* puntatore allo stack */ int *tos; /* punta alla cima dello stack */ int *bos; /* punta alla coda dello stack */ int stack[MAX]; void calc(void) { int answer, a, b; char in[80], out[80]; MS-DOS um 59 di 138 p = stack; tos = p; bos = p+MAX-1; tsrwindow(1); do { tsrwindow_xy(1, 0, 0); tsrwindow_cleol(1); tsrwindow_puts(1, ": "); /* prompt del calcolatore */ tsrwindow_gets(1, in); tsrwindow_puts(1, "\n"); tsrwindow_cleol(1); switch(*in) { case '+': a = pop(); b = pop(); answer = a+b; push(a+b); break; case '-': a = pop(); b = pop(); answer = b-a; push(b-a); break; case '*': a = pop(); b = pop(); answer = b*a; push(b*a); break; case '/': a = pop(); b=pop(); if(a==0) { tsrwindow_puts(0,"Divisione per 0.\n"); break; } answer = b/a; push(b/a); break; default: push(atoi(in)); continue; } itoa(answer, out, 10); tsrwindow_puts(1, out); } while(*in); tsrdeactive(1); } /* aggiunge un numero allo stack, restituisce 1 se l’operazione ha successo, altrimenti restituisce 0 */ push(int i) { if(p>bos) return (0); *p=i; p++; return (1); } /* toglie dallo stack l’ultimo elemento inserito, restituisce 0 MS-DOS um 60 di 138 se nello stack non vi è alcun elemento */ pop(void) { p--; if(p<tos) { p++; return (0); } return (*p); } /*********************************************************/ /* Blocco appunti di tipo pop-up */ /*********************************************************/ #define MAX_NOTE 10 char notes[MAX_NOTE][80]; void notepad(void) { static first=1; register int i, j, k; union inkey { char ch[2]; int i; } c; char ch; /* inizializza gli appunti, se necessario */ if(first) { for(i=0; i<MAX_NOTE; i++) *notes[i] = '\0'; first = !first; } tsrwindow(0); /* visualizza gli appunti esistenti */ for(i=0; i<MAX_NOTE; i++) { if(*notes[i]) tsrwindow_puts(0, notes[i]); tsrwindow_putchar(0, '\n'); } tsrwindow_xy(0, 0, 0); for(i=0;;) { c.i = readkey(); /* legge il tasto */ if(tolower(c.ch[0])==27) { /* ESC per uscire */ tsrdeactive(0); break; } /* se si tratta di un tasto normale */ if(isprint(c.ch[0]) || c.ch[0]=='\b') { tsrwindow_cleol(0); notes[i][0] = c.ch[0]; j = 1; tsrwindow_putchar(0, notes[i][0]); do { ch = tsrwindow_getche(0); if(ch=='\b') { if(j>0) { j--; tsrwindow_bksp(0); MS-DOS um 61 di 138 } } else { notes[i][j] = ch; j++; } } while(notes[i][j-1]!='\r'); notes[i][j-1] = '\0'; if(i<MAX_NOTE-1) i++; tsrwindow_putchar(0, '\n'); } else { /* se si tratta di un tasto speciale */ switch(c.ch[1]) { case 72: /* freccia in su */ if(i>0) { i--; tsrwindow_upline(0); } break; case 80: /* freccia in giu */ if(i<MAX_NOTE-1) { i++; tsrwindow_downline(0); } break; case 63: /* F5: cancella il blocco appunti */ tsrwindow_cls(0); for(k=0; k<MAX_NOTE; k++) *notes[k] = '\0'; tsrwindow_xy(0, 0, 0); } } } } /*****************************************************************/ /* semplice funzione che rende criptico il contenuto di un file, codifica semplicemente ciascun byte del file effettuandone il complemento, quindi per decodificare e’ sufficiente effettuare ancora una codifica, infatti il complemento del complemento di un byte e’ il byte stesso, la parte di codifica del file e’ piccola, ciò che rende complesso è il fatto che il tutto deve avvenire all’interno del TSR. */ void code(void) { int fd, num; char ch, fname[80], far *old_dta; long sk; old_dta = getdta(); /* memorizza la vecchia DTA */ setdta(MK_FP(_psp, 0x80)); /* costruisce la nuova DTA */ tsrwindow(2);tsrwindow_xy(2, 0, 0); tsrwindow_puts(2, "Inserire il nome del file: "); tsrwindow_gets(2, fname); if((fd = _open(fname, O_RDWR)) < 0) { tsrwindow_xy(2, 0, 0); tsrwindow_cleol(2); MS-DOS um 62 di 138 tsrwindow_puts(2, "File non apribile. Premere un tasto.\n"); tsrwindow_getche(2); tsrdeactive(2); setdta(old_dta); /* ripristina la vecchia DTA */ return; } num = 1; /* non si possono usare le routine standard ANSI C per l’I/O perché le function come fopen(), fread(), fwrite() non usano il sistema di allocazione dinamica della memoria utile in un TSR */ for(sk = 0; num==1 ; sk++) { lseek(fd, sk, SEEK_SET); num = _read(fd, &ch, 1); ch = ~ch; /* effettua il complemento di ogni byte */ lseek(fd, sk, SEEK_SET); if(num==1) _write(fd, &ch , 1); }; _close(fd); tsrdeactive(2); setdta(old_dta); /* ripristina la vecchia DTA */ } /* FUNZIONI DI FINESTRA: visualizza una finestra pull-down */ void tsrwindow(int num) /* numero di finestra */ { if(!frame[num].active) { /* non correntemente utilizzata */ save_video(num); /* memorizza lo schermo corrente */ frame[num].active=1; } /* imposta il flag allo stato attivo */ if(frame[num].border) tsrdraw_border(num); tsrdisplay_header(num); /* visualizza la finestra */ } /* costruisce una struttura per una finestra pull-down, è restituito 1 se la struttura può’ essere costruita, altrimenti è restituito 0 */ make_tsrwindow( int num, /* numero di finestra*/ char *header, /* titolo della finestra */ int startx, int starty, /* coordinate dell’angolo in alto a sinistra */ int endx, int endy, /* coordinate dell’angolo in basso a destra */ int border /* se vale 0 non vi e’ alcun bordo */ ) { if(num>MAX_FRAME) { tsrwindow_puts(0, "Troppe finestre.\n"); return (0); } if((startx>78) || (startx<0) || (starty>24) || (starty<0)) { tsrwindow_puts(0, "Errore dimensionale."); return (0); } if((endx>79) || (endy>25)) { tsrwindow_puts(0, "La finestra non ci sta."); return (0); } /* costruisce la struttura */ frame[num].startx = startx; frame[num].endx = endx; MS-DOS um 63 di 138 frame[num].starty = starty; frame[num].endy = endy; frame[num].p = wp; frame[num].header = header; frame[num].border = border; frame[num].active = 0; frame[num].curx = 0; frame[num].cury = 0; return (1); } /* disattiva una finestra e la elimina dallo schermo */ void tsrdeactive(int num) { /* riposiziona il cursore nell’angolo in alto a sinistra */ frame[num].curx = 0; frame[num].cury = 0; frame[num].active = 0; restore_video(num); } /* visualizza il titolo della finestra nell’apposita posizione */ void tsrdisplay_header(int num) { register int x, len; x = frame[num].startx; /* calcola la corretta posizione per centrare il titolo della finestra, se il valore risultante e’ negativo il titolo non ci sta all’interno della finestra */ len = strlen(frame[num].header); len = (frame[num].endx - x - len) / 2; if(len<0) return; /* non lo visualizza */ x = x +len; write_string(x, frame[num].starty,frame[num].header, NORM_VID); } /* disegna un bordo intorno alla finestra */ void tsrdraw_border(int num) { register int i; char far *v, far *t; v = vid_mem; t = v; for(i=frame[num].starty+1; i<frame[num].endy; i++) { v += (i*160) + frame[num].startx*2; *v++ = 179; *v = NORM_VID; v = t;v += (i*160) + frame[num].endx*2; *v++ = 179; *v = NORM_VID; v = t; } for(i=frame[num].startx+1; i<frame[num].endx; i++) { v += (frame[num].starty*160) + i*2; *v++ = 196; *v = NORM_VID; v = t; v += (frame[num].endy*160) + i*2; *v++ = 196; *v = NORM_VID;v = t; } /* disegna gli angoli del bordo */ MS-DOS um 64 di 138 write_char(frame[num].startx, frame[num].starty, 218, NORM_VID); write_char(frame[num].startx, frame[num].endy, 192, NORM_VID); write_char(frame[num].endx, frame[num].starty, 191, NORM_VID); write_char(frame[num].endx, frame[num].endy, 217, NORM_VID); } /* scrive una stringa nella posizione corrente del cursore nella finestra specificata, restituisce 0 se la finestra non e’ attiva, altrimenti restituisce 1 */ tsrwindow_puts(int num, char *str) { /* verifica che la finestra sia attiva */ if(!frame[num].active) return (0); for( ; *str; str++) tsrwindow_putchar(num, *str); return (1); } /* scrive un carattere nella posizione corrente del cursore all’interno della finestra specificata, restituisce 0 se la finestra non e’ attiva, altrimenti restituisce 1 */ tsrwindow_putchar(int num, char ch) { int x, y; char far *v; /* verifica che la finestra sia attiva */ if(!frame[num].active) return (0); x = frame[num].curx + frame[num].startx + 1; y = frame[num].cury + frame[num].starty + 1; v = vid_mem; v += (y*160) + x*2; /* calcola l’indirizzo */ if(y>=frame[num].endy) return (1); if(x>=frame[num].endx) return (1); if(ch=='\n') { /* carattere di newline */ y++; x = frame[num].startx+1; v = vid_mem; v += (y*160) + x*2; /* calcola l’indirizzo */ frame[num].cury++; /* incrementa la Y */ frame[num].curx = 0; /* azzera la X */ } else { frame[num].curx++; *v++ = ch; /* scrive il carattere */ *v++ = NORM_VID; /* attributo video normale */ } tsrwindow_xy(num, frame[num].curx, frame[num].cury); return (1); } /* posiziona il cursore in una finestra alla locazione specificata, restituisce 0 se e’ fuori dai limiti, altrimenti restituisce un valore diverso da 0 */ tsrwindow_xy(int num, int x, int y) { if(x<0 || x+frame[num].startx>=frame[num].endx-1) return (0); if(y<0 || y+frame[num].starty>=frame[num].endy-1) return (0); frame[num].curx = x; MS-DOS um 65 di 138 frame[num].cury = y; goto_xy(frame[num].startx+x+1, frame[num].starty+y+1); return (1); } /* legge una stringa da una finestra */ void tsrwindow_gets(int num, char *s) { char ch, *temp;temp = s; for(;;) { ch = tsrwindow_getche(num); switch(ch) { case '\r': /* è stato premuto il tasto INVIO */ *s = '\0';return; case '\b': /* tasto di cancellazione */ if(s>temp) { s--; frame[num].curx--; if(frame[num].curx<0) frame[num].curx = 0; tsrwindow_xy(num, frame[num].curx, frame[num].cury); write_char(frame[num].startx+ frame[num].curx+1, frame[num].starty+frame[num].cury+1, ' ', NORM_VID); } break; default: *s = ch; s++; } } } /* input di dati all’interno di una finestra, restituisce il codice di scansione a 16 bit */ tsrwindow_getche(int num) { union inkey { char ch[2]; int i; } c; if(!frame[num].active) return 0; /* la finestra non e’ attiva */ tsrwindow_xy(num, frame[num].curx, frame[num].cury); c.i = readkey(); /* legge il tasto */ if(c.ch[0]) { switch(c.ch[0]) { case '\r': /* è stato premuto il tasto INVIO */ break; case '\b': /* tasto di cancellazione */ break; default: if(frame[num].cury+frame[num].starty < frame[num].endy-1) { write_char(frame[num].startx+frame[num].curx+1, frame[num].starty+frame[num].cury+1, c.ch[0], NORM_VID); frame[num].curx++; } } if(frame[num].curx < 0) frame[num].curx = 0; if(frame[num].curx+frame[num].startx > frame[num].endx-2) MS-DOS um 66 di 138 frame[num].curx--; tsrwindow_xy(num, frame[num].curx, frame[num].cury); } return (c.i); } /* cancella fino al termine della linea */ void tsrwindow_cleol(int num) { register int i, x, y; x = frame[num].curx; y = frame[num].cury; tsrwindow_xy(num, frame[num].curx, frame[num].cury); for(i=frame[num].curx; i<frame[num].endx-1; i++) tsrwindow_putchar(num,' '); tsrwindow_xy(num, x, y); } /* cancella una finestra */ void tsrwindow_cls(int num) { register int i, j; char far *v; for(i=frame[num].starty+1; i<frame[num].endy; i++) for(j=frame[num].startx+1; j<frame[num].endx; j++) { v = vid_mem; v += (i*160) + j*2; *v++ = ' '; /* scrive uno spazio */ *v++ = NORM_VID; } frame[num].curx = 0; frame[num].cury = 0; } /* muove il cursore di una linea verso l’alto, restituisce un valore diverso da 0 se l’operazione riesce, altrimenti restituisce 0 */ tsrwindow_upline(int num) { if(frame[num].cury > 0) { frame[num].cury--; tsrwindow_xy(num, frame[num].curx, frame[num].cury); return (1); } return (0); } /* muove il cursore di una linea verso il basso, restituisce un valore diverso da 0 se l’operazione riesce, altrimenti restituisce 0 */ tsrwindow_downline(int num) { if(frame[num].cury < frame[num].endy-frame[num].starty-1) { frame[num].cury++; tsrwindow_xy(num, frame[num].curx, frame[num].cury); return (1); } return (1); } /* torna indietro di un carattere */ void tsrwindow_bksp(int num) { if(frame[num].curx>0) { frame[num].curx--; tsrwindow_xy(num, frame[num].curx, frame[num].cury); MS-DOS um 67 di 138 tsrwindow_putchar(num, ' '); frame[num].curx--; tsrwindow_xy(num, frame[num].curx, frame[num].cury); } } /*********************************************************/ /* Funzioni video di basso livello */ /**************************************** ****************/ /* visualizza una stringa con l’attributo specificato */ void write_string(int x, int y, char *p, int attrib) { char far *v; v = vid_mem; v += (y*160) + x*2; /* calcola l’indirizzo */ for(; *p; ) { *v++ = *p++; /* scrive il carattere */ *v++ = attrib; /* scrive l’attributo */ } } /* scrive un carattere con l’attributo specificato */ void write_char(int x, int y, char ch, int attrib) { char far *v; v = vid_mem; v += (y*160) + x*2; *v++ = ch; /* scrive il carattere */ *v = attrib; /* scrive l’attributo */ } /* memorizza una porzione dello schermo */ void save_video(int num) { register int i,j; char *buf_ptr, far *v, far *t; buf_ptr = frame[num].p; v = vid_mem; for(i=frame[num].startx; i<frame[num].endx+1; i++) for(j=frame[num].starty; j<frame[num].endy+1; j++) { t = (v + (j*160) + i*2); *buf_ptr++ = *t++; *buf_ptr++ = *t; *(t-1) = ' '; } /* cancella la finestra */ } /* ripristina una porzione dello schermo */ void restore_video(int num) { register int i,j; char far *v, far *t, *buf_ptr; buf_ptr = frame[num].p; v = vid_mem; t = v; for(i=frame[num].startx; i<frame[num].endx+1; i++) for(j=frame[num].starty; j<frame[num].endy+1; j++) { v = t; v += (j*160) + i*2; *v++ = *buf_ptr++; /* scrive il carattere */ *v = *buf_ptr++; } /* scrive l’attributo */ MS-DOS um 68 di 138 frame[num].active = 0; /* restore_video */ } /* restituisce il modo video corrente */ video_mode(void) { union REGS r; r.h.ah = 15; /* prende il modo video */ return int86(0x10, &r, &r) & 255; } /* restituisce il codice a 16 bit della scansione di tastiera */ readkey(void) { union REGS r; r.h.ah = 0; return int86(0x16, &r, &r); } /* posiziona il cursore alle coordinate X,Y specificate */ void goto_xy(int x, int y) { union REGS r; r.h.ah = 2; /* funzione di indirizzamento cursore */ r.h.dl = x; /* coordinata colonna */ r.h.dh = y; /* coordinata riga */ r.h.bh = 0; /* pagina video */ int86(0x10, &r, &r); } /* dispone il puntatore vid_mem alla partenza della memoria video */ void set_vid_mem(void) { int vmode = video_mode(); if((vmode!=2) && (vmode!=3) && (vmode!=7)) { printf("Il modo video dev’essere testo a 80 colonne."); exit(1); } /* determina l’indirizzo appropriato della RAM video */ if(vmode==7) vid_mem = (char far *) MK_FP(0xB000, 0000); else vid_mem = (char far *) MK_FP(0xB800, 0000); } /* legge e memorizza le coordinate del cursore */ void cursor_pos(void) { union REGS i, o ;i.h.bh = 0; i.h.ah = 3; int86(16, &i, &o); old_row = o.h.dh; old_col = o.h.dl; } MS-DOS um 69 di 138 MEMORIA memoria convenzionAle Da 0 a (640 KB - 1), dato che MS-DOS gestisce direttamente la memoria convenzionale, non è necessario un gestore di memoria aggiuntivo per l’utilizzo di questo tipo di memoria. Tutte le applicazioni richiedono memoria convenzionale. HMA (HIGH MEMORY area) Da 1 M a 1 M + (64 KB - 16) (10FFEFH), occupa i primi 64 KB di memoria estesa. Lo schema d’indirizzamento introduce anche un insolito cavillo che è usato da MS-DOS: i registri del segmento con valori tra F001H e FFFFH hanno una parte dei loro segmenti che si trova prima di 1 MB. Per esempio, con CS uguale a F001H, un salto a FFF4H va all’indirizzo 100004H, quattro byte prima dell’inizio della memoria. Allo stesso modo, con DS uguale a FFFFH, un’istruzione che prova a caricare il byte a FFFFH farà riferimento all’indirizzo 10FFFFH, che equivale a 1 MB + 65519. I 65520 byte tra 100000H e 10FFEFH sono chiamati HMA; sull’8088, l’H/W ignora il 21simo bit (A0..A19) per cui gli indirizzi sono mappati da zero a 65519. Sull’80286 e le CPU successive, il loro comportamento dipende da come è collegato il piedino dell’indirizzo A20 sulla CPU; se esso è collegato per funzionare come gli altri piedini, si può usare come memoria HMA e lo stesso MS-DOS vi può risiedere, ma, se esso è messo a terra, forzato a 0, allora tutti gli indirizzi tra 100000H e 10FFFFH saranno compresi tra 00000H e FFFFFH. Per essere pienamente compatibile con l’8088, il piedino deve essere messo a terra perché qualche S/W furbo può generare indirizzi sopra 1MB aspettandosi che questi saranno nascosti tra gli indirizzi bassi. In teoria, sull’8088 l’indirizzo 10004H è un sinonimo legale di 4, wrap around, ma la sua legalità non sottintende, comunque, che sia una buona pratica di programmazione. L’indirizzo più alto cui si può accedere con questo meccanismo è dato da FFFFH:FFFFH ovvero, 10FFEFH, pertanto anche se ufficialmente l’HMA impegna 64 KB, in realtà non ne sono utilizzabili gli ultimi 16 byte. Il venditore di H/W, allora, è di fronte ad una scelta: o abilitare HMA e in tal modo permettere a MS-DOS di girare sopra 1 MB, liberando 64 KB di memoria convenzionale o rendere compatibile l’8088. Il gestore è HIMEM.SYS, MS-DOS gestisce questa area con il comando DOS = HIGH. Le funzioni dello standard XMS (Extended Memory System) INT 2FH 4300H Check XMS installation. INT 2FH 4310H Get XMS driver entry point. INT 2FH 00H Get XMS version number. INT 2FH 01H Request high memory area. INT 2FH 02H Release high memory area. INT 2FH 03H Global enable A20. INT 2FH 04H Global disable A20. INT 2FH 05H Local enable A20. INT 2FH 06H Local disable A20. INT 2FH 07H Query A20 line. INT 2FH 8H Query free extended memory. INT 2FH 9H Allocate extended memory block. INT 2FH AH Release extended memory block. MS-DOS um 70 di 138 INT 2FH INT 2FH INT 2FH INT 2FH INT 2FH INT 2FH INT 2FH BH CH DH EH FH 0H 1H Move extended memory block. Lock extended memory block. Unlock extended memory block. Get handle information. Reallocate extended memory block. Request upper memory block. Release upper memory block. I codici di errore delle chiamate al driver XMM (eXtended Memory Manager) AX = 0001H Nessun errore. AX = 0000H Errore, codice in BL. 80H Funzione sconosciuta. 82H Errore sulla linea A20. 8EH Errore generale di XMM. 90H HMA non disponibile. 91H HMA già occupata. A0H Non c’è XMS libera. A9H Errore di parità. AAH UMB non bloccato. B1H Nessun UMB disponibile. La verifica della presenza di XMS avviene tramite l’int 2FH: basta chiamarlo con AX uguale a 4300H e verificare se in uscita risulta AL uguale a 80H. In caso affermativo esiste nel PC un driver XMS, detto XMM. Posto in AX 4310H e ripetuta la chiamata all’int 2FH, si ottiene in ES:BX l’indirizzo del driver XMM, contrariamente ad altri servizi offerti nel PC, questo driver si chiama direttamente con una CALL e non indirettamente tramite interrupt. L’applicazione principale EXTMEM.C utilizza il modulo EXTMEM.H. Dopo aver verificato la presenza di XMS e aver ottenuto l’indirizzo del driver XMM, il programma controlla l’ammontare di XMS presente, nonché, tenuto conto degli EMB (Extended Memory Block) già allocati da parte di altre applicazioni, la massima grandezza che può essere assegnata ad un nuovo eventuale EMB. Poiché i blocchi di EMB sono spostabili, (s)bloccabili e di dimensione variabile, può accadere che l’XMS sia frammentata in più parti e che pertanto non sia possibile allocare in un solo EMB il totale dello spazio ancora disponibile. Si passa quindi, se c’è XMS libera, al tentativo di allocare un EMB da 64 KB. Nel caso l’operazione riesca si mostrano se e quali blocchi EMB siano correntemente allocati nella XMS, nonché il numero di handle ancora disponibili per la creazione di nuovi blocchi, quindi si libera l’EMB ora utilizzato. L’applicazione prosegue verificando lo stato della linea A20; ma non basta, occorre anche che la linea sia abilitata. Quindi si mostra il contenuto della word agli indirizzi, 0000:0000 e FFFF:0010 equivale a 10000:0000. In generale i due valori, in quanto contenuto di due diverse locazioni di memoria, saranno differenti, infine si controlla se è libera od occupata la HMA. File EXTMEM.H #include <dos.h> #include <stdio.h> #define XMS_INT #define ASK_XMS #define XMS_ADR #define XMS_VER #define XMS_USE_HMA MS-DOS 0x2f 0x4300 0x4310 0x00 0x01 um 71 di 138 #define XMS_FREE_HMA 0x02 #define XMS_GLOBAL_A20_ON 0x03 #define XMS_GLOBAL_A20_OFF 0x04 #define XMS_LOCAL_A20_ON 0x05 #define XMS_LOCAL_A20_OFF 0x06 #define XMS_STATUS_A20 0x07 #define XMS_SIZE 0x08 #define XMS_ALLOC_EMB 0x09 #define XMS_FREE_EMB 0x0A #define XMS_MEMCOPY 0x0B #define XMS_LOCK_EMB 0x0C #define XMS_UNLOCK_EMB 0x0D #define XMS_INFO_EMB 0x0E #define XMS_MODIFY_EMB 0x0F #define XMS_ALLOC_UMB 0x10 #define XMS_FREE_UMB 0x11 #define XMS_NO_ERR 0x0001 typedef far (*LPFN) (void); typedef struct { unsigned a, b; } XMS_DAT; typedef struct { unsigned a, b, c, d; } XMS_INFO; LPFN XMM_entry; int Is_XMS(LPFN *); XMS_DAT XMS_VerRev(void); XMS_DAT XMS_GetSize(void); XMS_DAT XMS_EMB_Alloc(unsigned); XMS_INFO XMS_EMB_Info(unsigned); unsigned XMS_Generic(char, unsigned); int Is_XMS(LPFN *p) { struct REGPACK reg; reg.r_ax = ASK_XMS; intr(XMS_INT, ®); if ((reg.r_ax & 0x00ff) != 0x80) return(0); /* non trovo XMS driver */ reg.r_ax = XMS_ADR; intr(XMS_INT, ®); *p = XMM_entry = (LPFN) MK_FP(reg.r_es, reg.r_bx); return(1); } XMS_DAT XMS_VerRev(void) { int i,j; XMS_DAT VerRev; if (XMM_entry) { asm mov ah,XMS_VER; asm call XMM_entry; asm mov i,ax; /* numero di Versione */ asm mov j,bx; /* numero di Revisione */ } else { puts("\nCall to XMS_VR, w/o XMM-entry setup!\007\n"); exit(2); MS-DOS um 72 di 138 } VerRev.a =i; VerRev.b =j; return(VerRev); } XMS_DAT XMS_GetSize(void) { int i,j; XMS_DAT Size; if (XMM_entry) { asm mov ah,XMS_SIZE; asm call XMM_entry; asm mov i,dx; /* quantità di memoria XMS totale */ asm mov j,ax; /* max EMB allocabile */ } else { puts("\nCall to XMS_GetSize, w/o XMM_entry setup!\007\n"); exit(XMS_SIZE); } Size.a = i; Size.b = j; return(Size); } XMS_DAT XMS_EMB_Alloc(unsigned Size) { int i = Size, j, k; XMS_DAT Handle; if (XMM_entry) { asm mov ah,XMS_ALLOC_EMB; asm mov dx,i; asm call XMM_entry; asm mov i,dx; /* handle */ asm mov j,ax; /* codoce errore */ asm mov bh,0 asm mov k,bx; } else { puts("\nCall to XMS_EMB_Alloc, w/o XMM_entry setup!\007\n"); exit(XMS_ALLOC_EMB); } Handle.a = i; Handle.b = (j ? 0 : k); return(Handle); } XMS_INFO XMS_EMB_Info(unsigned Handle) { unsigned i = Handle, j; unsigned char k, l; XMS_INFO Info; if (XMM_entry) { asm mov ah,XMS_INFO_EMB; asm mov dx,i; asm call XMM_entry; asm mov i,dx; /* size (oppure 0 se errore) */ asm mov j,ax; /* codice errore */ asm mov k,bh; asm mov l,bl; MS-DOS um 73 di 138 } else { puts("\nCall to XMS_EMB_Info w/o XMM_entry setup!\007\n"); exit(XMS_INFO_EMB); } Info.a = i; Info.b = (i ? 0 : 1); Info.c = k; Info.d = l; return(Info); } unsigned XMS_Generic(char XMS_Id, unsigned Parm) { char i = XMS_Id; unsigned j = Parm, k = 0; if (XMM_entry) { asm mov ah,i; asm mov dx,j; asm call XMM_entry; asm mov j,ax; asm mov bh,0 asm mov k,bx; } else { puts("\nCall to XMS_Generic, w/o XMM_entry setup!\007\n"); exit(XMS_Id); } if (j == XMS_NO_ERR) k = 0; return(k); } File EXTMEM.C #include <stdio.h> #include <conio.h> #include <process.h> #include “extmem.h” #define EMB_SIZE 64 #define HMA_SIZE 64 int main(void) { unsigned i,j; float v, r; LPFN lpfn_XMS; XMS_DAT XMS_Ver, XMS_Size, XMS_EMB; XMS_INFO XMS_EMBs; clrscr(); if (!Is_XMS(&lpfn_XMS)) { puts("\nNon c’e' memoria XMS (e relativo driver XMM)!\007\n"); exit(1); } puts("\nVerificata la presenza di memoria XMS e relativo driver XMM."); XMS_Ver = XMS_VerRev(); v = (XMS_Ver.a >> 8) + (XMS_Ver.a & 0x00ff) * 0.01; r = (XMS_Ver.b >> 8) + (XMS_Ver.b & 0x00ff) * 0.01; printf("Versione XMM : %.2f (Revisione: %.2f)\n", v, r); MS-DOS um 74 di 138 XMS_Size = XMS_GetSize(); printf("Memoria XMS presente : %5u KB\n", XMS_Size.a); printf("Max EMB allocabile : %5u KB (meno HMA_SIZE)\n", XMS_Size.b); if (((int)XMS_Size.a - HMA_SIZE) >= EMB_SIZE) { XMS_EMB = XMS_EMB_Alloc(EMB_SIZE); if (XMS_EMB.b) printf("\n\007Errore %#x in XMS_ALLOC_EMB\n"); else { printf("\nAllocazione EMB da %u KB ok. Handle #%u\n",EMB_SIZE, XMS_EMB.a); for (i=1; i<=XMS_EMB.a; i++) { XMS_EMBs = XMS_EMB_Info(i); printf("\nInfo su EMB #%u : ",i); if (XMS_EMBs.b) printf("(errore %#x)"); else { printf("%5u KB %s", XMS_EMBs.a,(XMS_EMBs.c ? "(locked)" : "")); if (i == XMS_EMB.a) j = XMS_EMBs.d; } } printf("\nDisponibili ancora : %5u handle XMS\n", j); i = XMS_Generic(XMS_FREE_EMB, XMS_EMB.a); if (i) printf("\n\007\Errore %#x in XMS_FREE_EMB\n"); else printf("\nDeallocazione EMB da %u KB ok!\n", EMB_SIZE); } } i = XMS_Generic(XMS_STATUS_A20, 0); printf("\nStato linea A20: %s\n", i ? "off" : "On"); if (i && XMS_Generic(XMS_GLOBAL_A20_ON,0)) printf("\007Impossibile attivare linea A20!!\n"); else { puts("I prossimi due valori dovrebbero differire: "); printf("Contenuto 0000:0000 : %5u\n", *(unsigned far *)MK_FP(0x00,0x00)); printf("Contenuto FFFF:0010 : %5u ", *(unsigned far *)MK_FP(0xffff,0x10)); printf(" (FFFF:0010 = 10000:0000)\n"); } i = XMS_Generic(XMS_USE_HMA, 0xffff); switch(1) { case 0: puts("\nHMA allocata ok"); i = XMS_Generic(XMS_FREE_HMA, 0); if (i) puts("Errore deallocazione HMA!\007"); else puts("HMA deallocazione ok"); break; case 0x90: puts("\nNon c’e' HMA in questo PC!"); break; case 0x91: puts("\nHigh Memory Area : in uso."); break; default: printf("\nErrore %#x, dopo XMS_USE_HMA\007", i); } MS-DOS um 75 di 138 getch(); return(0); } xms Da 1 MB a 16 MB - 1 per 80286, da 1 MB a 4 GB - 1 per 80386. MS-DOS opera in real mode, la memoria estesa è accessibile solo in protected mode. L’utilizzo di memoria estesa implica che il programmatore si è avvalso di strumenti chiamati DOS EXTENDER, il che significa semplicemente l’introduzione di una serie di nuove problematiche. Un sistema chiamato DOS EXTENDER sostituisce completamente una serie di chiamate a MS-DOS legate strettamente alla gestione della memoria. In pratica, per utilizzare tutta la memoria presente in un PC è necessario riscrivere alcune funzioni del SO. Anche strumenti quali linker, compilatori, librerie delle funzioni di run-time e naturalmente anche debugger e profiler devono essere in grado di operare con un particolare DOS EXTENDER. Anche Windows contiene le funzioni base per operare con XMS, alla precisa condizione che le applicazioni siano appositamente create per operare nell’ambiente grafico. La nuova serie di funzionalità introdotte con un DOS EXTENDER, ovvero l’insieme di routine che sostituiscono parti di MS-DOS per ampliare le caratteristiche del SO, sono divise in standard riconosciuti in base alle modalità di accesso che sono previste. VCPI (Virtual Control Program Interface) Introdotto dalla società DeskView, creatrice di un sistema multitasking che per operare necessitava di più memoria, il sistema si è rapidamente diffuso per la serie di strumenti che la stessa DeskView poneva a disposizione. DPMI (DOS Protected Mode Interface) La versione di Windows 3.0 introduceva, tra le varie novità, un sistema nuovo per la gestione della memoria estesa, lo standard VCPI era reso di fatto obsoleto dal rilascio del gestore di XMS chiamato HIMEM.SYS. In pratica tra l’applicazione, che opera in protected mode e MS-DOS si pongono le routine del DPMI. Alcune metodologie di accesso alla memoria, in particolare per quanto riguarda la grafica, devono essere profondamente ridefinite per operare opportunamente in protected mode. La grafica, in un sistema che utilizza un DOS EXTENDER, implica che la CPU debba passare dal real mode, ovvero in una modalità di accesso secondo MS-DOS, in protected mode, questa fase di passaggio, effettuata ogniqualvolta sia necessario riferirsi a servizi DOS indispensabili introduce un tempo di ritardo. Le funzioni dello standard DPMI INT 2FH 1686H Get CPU mode. INT 2FH 168AH Get API entry point. INT 31H 0100H Allocate DOS memory block. INT 31H 0101H Release DOS memory block. INT 31H 0200H Get real mode interrupt vector. INT 31H 0201H Set real mode interrupt vector. INT 31H 0204H Get protected mode interrupt vector. INT 31H 0205H Set protected mode interrupt vector. INT 31H 0400H Get DPMI version. uma (Upper memory area) Da 640 KB a (1MB - 1), inizialmente era riservata per l’H/W del sistema, ad esempio la MS-DOS um 76 di 138 RAM video, le ROM BASIC e altre funzioni d’I/O. Sopra i 640 KB non era presente alcuna RAM ordinaria, così il SO, i driver di dispositivo e tutte le applicazioni utente e i dati erano limitati alla memoria convenzionale di 640 KB. A posteriori, la divisione dello spazio degli indirizzi dell’8088 nella memoria convenzionale di 640 KB e la UMA di 384 KB fu un errore. I dispositivi d’I/O non necessitano molto dello spazio degli indirizzi, mentre le applicazioni ne hanno maggiormente bisogno, così una divisione di 832 KB per le applicazioni e 192 KB per i dispositivi d’I/O sarebbe stata una scelta migliore. Essa attualmente non può essere modificata perché esistono migliaia di schede d’I/O per il PC, molte delle quali mettono le ROM e le RAM specializzate su indirizzi sparsi dappertutto sull’UMA. Anche se molti PC hanno da 200 KB a 300 KB di spazio d’indirizzi non utilizzato, chiamati UMB (Upper Memory Block) nella memoria superiore, gli indirizzi esatti che sono liberi variano da macchina a macchina; inoltre essi non sono blocchi contigui, bensì un insieme di buchi tra le schede d’I/O. A dispetto di tutte queste complicazioni, partendo con la versione 5.0 di MS-DOS, la Microsoft decise di permettere all’80386 e alle CPU superiori di usare questo spazio degli indirizzi mappando parti della memoria estesa nei buchi. Allora, ad esempio, se una particolare macchina non ha dispositivi d’I/O, ROM o RAM video agli indirizzi da 640 KB a 704 KB, da 768 KB a 800 KB e da 896 KB a 960 KB, può fare in modo che MS-DOS mappi 160 KB della sua memoria estesa in queste celle, usandole come RAM; per quanto riguarda la CPU, tutta la memoria che rientra in 1 M è trattata allo stesso modo. Fu l’IBM a decidere di allocare 384 KB superiori all’I/O creando una barriera a 640 KB. Il mappare la memoria estesa nelle celle in UMA è solo un tentativo di eliminare alcuni danni. L’area superiore della memoria è disponibile solo per le applicazioni dall’80386 in avanti poiché le CPU più piccole non hanno paginazione H/W e non possono mappare fisicamente la memoria estesa negli indirizzi virtuali nell’intervallo da 640 KB a 1 MB. Quando MS-DOS parte, legge il file CONFIG.SYS in cui l’utente può specificare che lo stesso MS-DOS può essere sistemato in HMA invece che in memoria convenzionale; è possibile anche specificare che i driver di dispositivo e i TSR si devono tenere nell’area superiore della memoria con il comando DOS = UMB. Tutto ciò ha l’effetto di liberare un po’ di memoria in più all’interno del limite di 640 KB. Per gli utenti che hanno molti buffer, molti driver di dispositivo e molti TSR, portare tutto nella parte superiore della memoria, compreso MS-DOS, può significare liberare una considerevole parte della memoria convenzionale per le applicazioni utente. Il gestore di memoria superiore è EMM386.EXE. Overlay Il bisogno di più di 640 KB di spazio degli indirizzi è anteriore all’80286; a quel tempo si rivelò necessaria una soluzione compatibile con l’8088. La soluzione S/W che fornisce MS-DOS consiste in una chiamata di sistema che permette ad un’applicazione in esecuzione di caricare un file COM o EXE, chiamato overlay, nella memoria e poi riprendere il controllo. L’applicazione chiamante poi invoca una procedura di overlay e, quando questo ha finito, può deallocare la memoria di overlay e continuare; è libero di caricare questo e, in un secondo momento, altri overlay. In questo modo è possibile avere un numero di applicazioni, arbitrariamente grandi, che può essere contenuto in una quantità di memoria relativamente piccola, ma con sufficiente spazio su disco. La parola overlay significa letteralmente sovrapposto. MS-DOS um 77 di 138 Funzionamento Si carica in memoria l’applicazione principale, chiamata root overlay, essa contiene il codice per controllare il meccanismo di overlay, infatti nessun grosso aiuto è dato dal SO e può contenere anche tabelle e strutture di dati condivise. Poco tempo dopo essere partito, l’overlay di radice fa una chiamata al sistema che carica l’overlay di passo uno; a caricamento completato esso può chiamare la procedura principale nel passo uno usando l’istruzione di chiamata di procedura, eventualmente con passaggio dei parametri. Il passo uno gira e mette le informazioni nelle tabelle che si trovano nella root overlay. Al momento in cui esso termina, la procedura principale del passo uno restituisce il controllo al suo chiamante nella root overlay. A questo punto può richiedere il caricamento del passo due e quindi chiamarlo. Il passo due può leggere le informazioni che il passo uno ha messo nelle tabelle della root overlay. Se ne deduce che il meccanismo di overlay rende più facile la condivisione dell’informazione tra i differenti blocchi dell’applicazione: molte applicazioni di grande dimensione di MS-DOS usano questo meccanismo. VROOMM (Virtual Runtime Object Oriented Memory Manager) La Borland per il linguaggio C++ sotto MS-DOS, ha rilasciato questa tecnologia di gestione degli overlay, sviluppata inizialmente per uso interno e implementata in Reflex 2.0 e successivamente in Quattro. Permette di definire una zona di memoria variabile, non fissa, per il caricamento delle differenti parti di funzioni poste in overlay, possiede routine per il controllo del caricamento dei moduli di overlay. Questi controlli permettono di verificare quali sono i moduli più utilizzati e di effettuare calcoli sulla memoria disponibile durante l’esecuzione per mantenere sempre in memoria, quando possibile, i moduli più utilizzati. Memoria virtuale Le applicazioni Windows non utilizzano gli overlay, in quanto questi ultimi riserverebbero in modo esclusivo alcune aree di memoria, mentre la memoria è un bene comune, posto a disposizione di tutte le applicazioni attive, usano la memoria virtuale. Questa tecnica permette di accogliere richieste di utilizzo di RAM superiori alla quantità fisica presente. In questo caso è il gestore della memoria che effettua automaticamente uno scarico dei dati, appoggiandosi sull’hard disk, fornendo l’illusione alle applicazioni di avere una quantità di memoria superiore di quella reale. La memoria gestita con tecniche di memoria virtuale, può essere utilizzata sia per caricare MS-DOS um 78 di 138 applicazioni, sia dalle applicazioni stesse quando necessitano di ulteriore memoria per eseguire elaborazioni complesse che richiedono la presenza di grosse quantità di dati. Un particolare di estrema importanza è che le routine per la gestione degli overlay sono parte integrante dell’applicazione, contrariamente alle routine di gestione di memoria virtuale che sono incorporate nel SO e operano in modo trasparente a favore di tutte le applicazioni. Possono essere posti in overlay sia variabili, dinamiche e statiche, sia routine oggetti e quindi metodi. La scelta delle funzioni da porre in overlay dipende semplicemente dalle esigenze, per esempio la funzione che visualizza la videata di presentazione contenente il nome dell’applicazione e del suo creatore è una prima indicazione. Questo perché non è utilizzata durante l’esecuzione dell’applicazione, ma solamente all’inizio. I moduli di overlay possono essere posti in memoria espansa, estesa e caricati o scaricati da disco secondo il bisogno. Per utilizzare gli overlay secondo il metodo proposto con il gestore VROOMM è necessario attivare alcune opzioni del compilatore. O/A/Dos Overlay O/C/C/Model Large O/C/E/Dos Overlay O/L/S/Overlaid DOS EXE MS-DOS um 79 di 138 Esempio, il file Project chiamato VROOMM.PRJ, include quattro file sorgenti. Il primo di essi è l’applicazione principale MAIN.CPP e tre sono i moduli da porre in overlay chiamati rispettivamente 10VL.CPP, 20VL.CPP e 30VL.CPP. // Funzione: applicazione principale dell’esempio di uso degli overlay, main.cpp // Note: l’applicazione fa parte del progetto VROOMM.PRJ non può funzionare se // eseguito dall’interno dell’ambiente integrato !! #include <stdio.h> #include <conio.h> void ciao1(void); void ciao2(void); void ciao3(void); int main(void) { clrscr(); ciao1(); // richiamo della funzione ciao1 ciao2(); // richiamo della funzione ciao2 ciao3(); // richiamo della funzione ciao3 return (0); } // Funzione: prima parte dell’applicazione da porre in overlay, 10vl.cpp // Note: l’applicazione fa parte del progetto VROOMM.PRJ #include <stdio.h> void ciao1(void) { printf(“%s”,”Ciao 1\n”);} // Funzione: seconda parte dell’applicazione da porre in overlay, 20vl.cpp // Note: l’applicazione fa parte del progetto VROOMM.PRJ #include <stdio.h> void ciao2 (void) { printf(“%s”,”Ciao 2\n”);} // Funzione: terza parte dell’applicazione da porre in overlay, 30vl.cpp // Note: l’applicazione fa parte del progetto VROOMM.PRJ #include <stdio.h> void ciao3 (void) { printf(“%s”,”Ciao 3\n”);} MS-DOS um 80 di 138 È complesso comprendere se un modulo è stato inserito correttamente nella gestione di overlay o meno, l’uso del TurboProfiler permette di controllare con esattezza, mediante l’opzione View/Overlay, quali sono i moduli che sono posti sotto tale gestione, indicandone anche le dimensioni del codice. Un fatto molto importante, da sottolineare, è che l’utilizzo di routine contenute in moduli posti nell’area di overlay e di conseguenza il loro caricamento da disco se necessario, è gestito automaticamente dall’overlay manager di BorlandC e non è necessario indicare nulla al gestore di overlay inserendo, come in altri linguaggi, particolari istruzioni specifiche da parte del programmatore. L’uso di overlay è tipico di applicazioni professionali, nelle quali uno dei requisiti principali è la possibilità che qualsiasi utente, con qualsivoglia configurazione di PC e memoria, possa utilizzare con completezza l’applicazione fornitogli. Perché il modo di operare del gestore di overlay è comunque ottimizzato. Ad esempio, è chiaro che se la memoria a disposizione degli overlay, in una certa configurazione di PC, è sufficientemente grande, allora il gestore di overlay caricherà tutti i moduli in memoria. Cosa porre in overlay Come utilizzare al meglio le caratteristiche fornite dal gestore VROOMM. 1. È possibile impostare quanta memoria lasciare al gestore di overlay utilizzando in modo opportuno la variabile di ambiente _ovrbuffer; per esempio, per definire uno spazio di overlay di 128 KB e la definizione da effettuare è la seguente: unsigned _ovrbuffer = 0x2000; non c’è un numero magico di dimensione della memoria. 2. Porre in overlay parti di applicazioni tra loro indipendenti; ad esempio, in un foglio elettronico la gestione dei calcoli matematici e la visualizzazione dei grafici sono due moduli candidati ideali per essere posti in overlay. Cosa non porre in overlay 1. Gestioni particolari che ridefiniscono i vettori d’interrupt per il controllo di alcune funzioni di SO o funzioni legate strettamente a tempi di esecuzione non è opportuno che siano poste sotto il controllo di un gestore di overlay, per quanto sofisticato possa essere. 2. Evitare di porre in overlay parti che devono essere utilizzate da più moduli; in questo caso l’overlay, contenente fondamentali routine, sarebbe continuamente caricato e scaricato dal disco, influenzando negativamente le prestazioni di tutta l’applicazione. Ems (Expanded memory system) L’overlay funziona in maniera adeguata per applicazioni che sono formate da grosse quantità di codice che gira sequenzialmente, come i compilatori; essi funzionano meno bene quando un’applicazione ha bisogno di operare su una grossa struttura dati che non entra nello spazio degli indirizzi di 64 KB. Tre ditte, la Lotus, la INTEL e la Microsoft si misero insieme e idearono uno schema H/W detto memoria espansa con il quale una grande quantità di memoria si sarebbe potuta montare e usare sull’8088. La Lotus modificò il suo foglio elettronico 1-2-3 per poterlo usare, la Microsoft adeguò MSDOS per poterlo supportare e l’INTEL costruì una scheda speciale di memoria e il driver MS-DOS um 81 di 138 S/W relativo. Anche se le CPU 80286, 80386 in avanti non necessitavano di memoria espansa, poiché questa ormai esisteva, MS-DOS è fatto per supportarla e molte applicazioni la usano. Infatti, dalle macchine 386 in poi una parte di EMS è usata di solito per riempire le celle nella HMA e quello che rimane spesso è usato per simulare la memoria espansa. Questo schema sviluppato da tre industrie è stato standardizzato ed è conosciuto come LIM EMS (Lotus INTEL Microsoft Expanded Memory System), la versione 4.0 è quella che implementa migliori tecniche per velocizzare l’accesso alla memoria. L’idea di base di EMS è una vecchia tecnica chiamata commutazione di banco, bank switching. Lo spazio degli indirizzi di 1 MB del PC è diviso in 64 pagine ognuna di 16 KB. La memoria, 32 MB è divisa in porzioni di 2048 pagine da 16 KB ognuna. 16 KB = 16384 byte = offset della pagina 14 bit. 64 KB = 4 pagine da 16 KB = indirizzo delle pagine nel segmento 2 bit. 32 MB = 512 segmenti = indirizzo dei segmenti 9 bit. Indirizzo lungo 25 bit L’H/W speciale sulla scheda della memoria espansa mappa le 64 pagine virtuali in un insieme arbitrario di porzioni fisiche di memoria. Sebbene assomigli molto ad una paginazione ordinaria in effetti non lo è; infatti è esattamente l’opposto. Con la paginazione, il problema consiste nel fatto che non c’è sufficiente memoria fisica per mantenere uno spazio degli indirizzi virtuali per cui è necessario il mapping. Per esempio, un’applicazione sul 386 potrebbe avere bisogno di 64 MB di memoria mentre la macchina ne ha solo 16 MB; quello che fa la paginazione è assegnare una parte dei 64 MB di disco per mantenere l’immagine intera e poi portarlo in pagine individuali così come sono usate. Il problema che l’EMS prova a risolvere è quello di inserire grosse applicazioni e strutture dati in uno spazio degli indirizzi virtuali di 640 KB. Si supponga che un’applicazione stia facendo un calcolo su una matrice 1000X1000 di numeri in virgola mobile. Anche se la macchina ha gli 8 MB necessari di memoria fisica, non vi è modo d’indirizzarli, perché l’8088 non può generare indirizzi sopra 1 MB e quelli tra 640 KB e 1 MB sono riservati per i dispositivi d’I/O. L’effetto del S/W EMS è quello di permettere alle applicazioni di mappare una parte della memoria fisica nella porzione da 512 KB a 640 KB (page frame) e lavorare su di essa; ad esecuzione terminata essa è liberata e l’applicazione ve ne mappa un’altra parte. Al contrario della paginazione, che è trasparente, la memoria espansa è completamente visibile al programmatore o al più al compilatore o al suo sistema. Nulla avviene in modo automatico; dopotutto, per elaborare l’array di 8 MB, l’intero vettore dovrà essere eventualmente mappato nella page frame, un pezzo alla volta. Solo l’applicazione o il compilatore sanno di quale parte hanno bisogno in ogni momento. Su un 386 o più, che hanno l’H/W di paginazione, le pagine possono essere mappate dalla memoria estesa in un posto qualsiasi dello spazio degli indirizzi, per cui, su queste macchine, la memoria estesa si può usare per simulare la memoria espansa senza H/W speciale. Il gestore è EMM386.EXE, dato però che il gestore di EMS consente l’accesso solo a una quantità limitata di EMS alla volta, l’utilizzo risulta più lento rispetto a XMS. Per rendere possibile alle applicazioni di mappare e liberare la memoria in modo indipendente dal fatto che si usi la memoria estesa o quella espansa, EMS standard definisce le chiamate di sistema che le applicazioni possono fare e che il sistema può supportare, per mezzo di un driver di dispositivo per la memoria. Probabilmente sarebbe stato sufficiente fornire le quattro chiamate di sistema, ALLOCATE MEMORY (43H), RELEASE MEMORY (45H), SAVE PAGE MAP (47H) e RESTORE MS-DOS um 82 di 138 PAGE MAP (48H), ma i progettisti di EMS definirono quasi 40 chiamate di sistema. Inoltre, le precedenti 4 sono chiamate per chiedere tutti i tipi d’informazione di stato, quante pagine sono libere? La manipolazione della mappa, salva e ripristina una mappa di pagina e lo switch del contesto. L’ultimo è utile per le applicazioni tipo DOSSHELL e Windows, in cui molte applicazioni possono girare contemporaneamente, ognuna con il suo insieme di pagine. Il SO, per esempio, può allocare per i suoi scopi da 0 a 128 KB, poi allocare una parte dei 512 KB per l’applicazione 1, una seconda parte dei 512 KB per l’applicazione 2 e così via. Quando l’applicazione 1 sta girando, la sua parte di memoria espansa è mappata nello spazio degli indirizzi da 128 KB a 640 KB, ma quando è effettuato lo switch del contesto, l’applicazione 1 è mappata fuori e un’altra applicazione è mappata al suo posto. Disco RAM Quando è ancora disponibile memoria estesa, poiché MS-DOS non permette che le applicazioni girino su di essa ad eccezione di quando simulano la memoria espansa, la si può usare per un disco RAM nella memoria RAM del sistema per simulare un’unità disco. Tali dischi sono molto veloci perché le informazioni in essi contenute sono sempre in memoria, per contro però sono temporanei nel senso che quando il PC non è alimentato i dati memorizzati sono persi. Memoria cache Si usa una parte di RAM come cache per migliorare le prestazioni del disco. Mappa di memoria del PC DEC 0K (640 - 1) K 640 K (704 - 1) K 704 K 736 K (768 - 1) K 768 K 800 K (832 - 1) K 832 K (896 - 1) K 896 K (960 - 1) K 960 K (1024 - 1) K 1024 K (1088 - 1) K 1088 K ............ MS-DOS HEX 000000 09FFFF 0A0000 0AFFFF 0B0000 0B8000 0BFFFF 0C0000 0C8000 0CFFFF 0D0000 0DFFFF 0E0000 0EFFFF 0F0000 0FFFFF 100000 10FFFF 110000 ............ DESCRIZIONE Memoria convenzionale. Segmenti da 0 a 9. VGA (Video Graphics Array) Graphics. Buffer video monocromatico, oppure 32K di UMB Buffer video colori. VGA ROM. 32K di UMB. 64K di UMB. ROM BASIC IBM, oppure EMS PAGE FRAME, oppure 64K di UMB. BIOS ROM. HMA. XMS. um 83 di 138 Il comando MEM visualizza informazioni sulla quantità di memoria disponibile sia convenzionale sia superiore. Il comando MEM /F (Free) visualizza informazioni sulla quantità di memoria disponibile sia convenzionale sia superiore. Memoria convenzionale libera: Segmento Totale 0124B 304 (0K) 0125E 88.992 (87K) 02818 491.120 (480K) Spazio libero tot.: 580.416 (567K) Memoria superiore disponibile: Regione Maggiore disp. Totale disp. Dimensione tot. 1 0 (0K) 0 (0K) 158.480 (155K) Il comando MEM /C (Classify) classifica le applicazioni secondo la memoria occupata. Moduli che utilizzano memoria al di sotto di 1 MB: Nome Totale = Convenzionale MSDOS 16.221 (16K) 16.221 (16K) HIMEM 1.168 (1K) 1.168 (1K) EMM386 3.120 (3K) 3.120 (3K) COMMAND 5.056 (5K) 5.056 (5K) win386 14.192 (14K) 13.008 (13K) VSHIELD 51.696 (50K) 1.808 (2K) DOSKEY 4.144 (4K) 4.144 (4K) MOUSE 16.240 (16K) 16.096 (16K) KEYB 6.944 (7K) 6.944 (7K) WIN 2.096 (2K) 2.096 (2K) COMMAND 5.296 (5K) 5.296 (5K) ANSI 4.208 (4K) 0 (0K) SBCD 11.584 (11K) 0 (0K) IFSHLP 3.936 (4K) 0 (0K) SMARTDRV 28.928 (28K) 0 (0K) MS-DOS Memoria superiore 0 (0K) 0 (0K) 0 (0K) 0 (0K) 1.184 (1K) 49.888 (49K) 0 (0K) 144 (0K) 0 (0K) 0 (0K) 0 (0K) 4.208 (4K) 11.584 (11K) 3.936 (4K) 28.928 (28K) um 84 di 138 SHARE 17.920 (18K) 0 (0K) 17.920 (18K) MSCDEX 40.688 (40K) 0 (0K) 40.688 (40K) Libera 580.112 (567K) 580.112 (567K) 0 (0K) Riepilogo della memoria: Tipo di memoria Totale = Usata + Libera Convenzionale 655.360 75.248 580.112 Superiore 158.480 158.480 0 Riservato 393.216 393.216 0 Estesa (XMS) 7.181.552 6.132.976 1.048.576 memoria totale 8.388.608 6.759.920 1.628.688 Tot. inf. a 1 MB 813.840 233.728 580.112 Dim. massima di un programma eseguibile 580.096 (567K) Dim. massima di un blocco libero di memoria superiore 0 (0K) MS-DOS è residente nell’area di memoria alta. Il comando MEM /D (Debug) visualizza lo stato di tutti i moduli di memoria, dei driver e altre informazioni. Informazioni sulla memoria convenzionale: Segmento Totale Nome Tipo 00000 1.039 (1K) Vettore d’interruzione 00040 271 (0K) Area per le comunicazioni ROM 00050 527 (1K) Area per le comunicazioni DOS 00070 2.656 (3K) IO Dati di sistema CON Driver periferiche di sistema AUX Driver periferiche di sistema PRN Driver periferiche di sistema CLOCK$ Driver periferiche di sistema A: - C: Driver periferiche di sistema COM1 Driver periferiche di sistema LPT1 Driver periferiche di sistema LPT2 Driver periferiche di sistema LPT3 Driver periferiche di sistema COM2 Driver periferiche di sistema COM3 Driver periferiche di sistema COM4 Driver periferiche di sistema 00116 5.072 (5K) MSDOS Dati di sistema 00253 10.880 (11K) IO Dati di sistema 1.152 (1K) XMSXXXX0 Periferica installata=HIMEM 3.104 (3K) $MMXXXX0 Periferica installata=EMM386 2.080 (2K) FILES=40 256 (0K) FCBS=4 512 (1K) BUFFERS=10 624 (1K) LASTDRIVE=G 3.024 (3K) STACKS=9,256 004FB 80 (0K) MSDOS Programma di sistema 00500 64 (0K) COMMAND Dati 00504 2.928 (3K) COMMAND Programma 005BB 80 (0K) win386 Dati 005C0 2.064 (2K) COMMAND Ambiente 00641 1.808 (2K) VSHIELD Programma 006B2 4.144 (4K) DOSKEY Programma 007B5 16.096 (16K) MOUSE Programma MS-DOS um 85 di 138 00BA3 6.944 (7K) KEYB Programma 00D55 288 (0K) WIN Ambiente 00D67 1.808 (2K) WIN Programma 00DD8 304 (0K) win386 Ambiente 00DEB 12.624 (12K) win386 Programma 01100 304 (0K) COMMAND Dati 01113 2.928 (3K) COMMAND Programma 011CA 2.064 (2K) COMMAND Ambiente 0124B 304 (0K) MEM Ambiente 0125E 88.992 (87K) MEM Programma 02818 491.120 (480K) MSDOS - Libera -Informazioni sulla memoria superiore: Segmento Regione Totale Nome Tipo 0C952 1 19.680 (19K) IO Dati di sistema 4.192 (4K) CON Periferica installata=ANSI 11.568 (11K) MSCD001 Periferica installata=SBCD 3.856 (4K) IFS$HLP$ Periferica installata=IFSHLP 0CE20 1 144 (0K) MOUSE Ambiente 0CE29 1 28.928 (28K) SMARTDRV Programma 0D539 1 49.888 (49K) VSHIELD Dati 0E167 1 17.920 (18K) SHARE Programma 0E5C7 1 40.688 (40K) MSCDEX Programma 0EFB6 1 1.184 (1K) win386 Dati Riepilogo della memoria: Tipo di memoria Totale = Usata + Libera Convenzionale 655.360 75.248 580.112 Superiore 158.480 158.480 0 Riservato 393.216 393.216 0 Estesa (XMS) 7.181.552 6.132.976 1.048.576 memoria totale 8.388.608 6.759.920 1.628.688 Tot. inf. a 1 MB 813.840 233.728 580.112 Memoria accessibile utilizzando Int 15h 0 (0K) Dim. massima di un programma eseguibile 580.096 (567K) Dim. massima di un blocco libero di memoria superiore 0 (0K) MS-DOS è residente nell’area di memoria alta. XMS versione 2.00; driver versione 2.05 Implementazione della gestione della memoria Così come MS-DOS evita di avere una tabella centrale dei processi tenendo traccia dei processi per mezzo della catena dei PSP, esso usa lo stesso schema per la gestione della memoria. MS-DOS tiene traccia di tutti i blocchi contenuti nella memoria, sia di quelli liberi sia di quelli allocati. Questa operazione è eseguita verificando il contenuto di appositi blocchi di controllo, detti MCB (Memory Control Block) che precedono qualsiasi blocco libero o allocato di memoria. La verifica dell’MCB consente di determinare il tipo, la dimensione e le applicazioni contenute nel singolo blocco, tra quelli in cui è suddivisa la memoria del sistema e cui l’MCB considerato si riferisce. L’MCB ha dimensioni pari a 16 byte, un paragrafo, ma solo i primi 5 sono utilizzati. 1 byte = tipo di blocco: 4DH blocco in lista, 5AH fine lista. 2, 3 byte = contiene il PID, 0000H libero; un valore diverso da 0 indica che la zona di memoria specificata dall’MCB è allocata al PID. 4, 5 byte = dimensione del blocco in paragrafi escluso MCB. MS-DOS um 86 di 138 Esempio. 0A00:0000 4D 0008 1600 0A01:0000 blocchi allocati di proprietà del PID 0008 Indirizzo successivo: 0A00+1600+1=2001 2001:0000 4D 0113 0010 2002:0000 blocchi allocati di proprietà del PID 0113 Indirizzo successivo: 2001+0010+1=2012 2012:0000 5A 0000 7AEC 2013:0000 blocchi liberi Tecnicamente, gli MCB non formano una lista concatenata perché le intestazioni contengono le dimensioni piuttosto che i puntatori, ma l’effetto che si ottiene è lo stesso. Quando MS-DOS deve allocare la memoria, per caricare un processo figlio o un overlay, o per soddisfare una chiamata di sistema 48H di un’applicazione, esamina la catena di blocchi partendo dalla fine finché non trova un blocco sufficientemente grande. Se l’MCB scelto è troppo grande, se ne prende una parte e si crea un nuovo MCB per rappresentare la parte lasciata. Quando la memoria è liberata, gli MCB adiacenti liberi non sono messi insieme perché la catena di blocchi non è una lista concatenata doppia. La fusione dei blocchi avviene in un secondo momento quando la ricerca attraverso la catena parte dall’inizio. Come conseguenza di questo metodo di gestione della memoria un’applicazione con tabelle dinamiche, che costantemente alloca e libera memoria è probabile che possegga pezzi di memoria sparsi dappertutto nello spazio degli indirizzi; ciò è in contrasto con il modello Unix di un singolo segmento di dati che può crescere o restringersi come e quando è necessario. Di fatto la differenza è più piccola di quanto sembra poiché poche applicazioni Unix usano direttamente la chiamata di sistema brk. La maggior parte usa le funzioni del linguaggio C: malloc, free e realloc che hanno lo stesso effetto delle chiamate di sistema di MS-DOS. La differenza reale è che, in MS-DOS, il SO mantiene la lista libera, mentre, in Unix, essa è mantenuta a due livelli. Il SO tiene traccia dei blocchi di memoria allocati e deallocati e malloc gestisce il contenuto dei segmenti dati. Sebbene lo schema di MCB funzioni per la memoria UMA; esso non funziona per la XMS, è quindi necessario installare uno o più driver di memoria estesa. MS-DOS non prevede né la paginazione né lo swap, se un processo tenta di allocare la memoria e non c’è nessuna parte di essa libera o se un processo tenta di fare una fork e non vi è sufficiente memoria in cui inserire il figlio, la chiamata di sistema restituisce semplicemente un codice di errore; il ripristino è lasciato completamente al chiamante. chiamate di sistema Le chiamate di sistema per la gestione della memoria in MS-DOS sono più complicate di quelle in Unix, permettono alle applicazioni di allocare, liberare e ridimensionare i blocchi di memoria. Nell’allocare la memoria MS-DOS usa un algoritmo del tipo first fit o best fit, il primo che può essere contenuto o quello che può essere contenuto nel modo migliore. Serve anche indirettamente a controllare quanta memoria è ancora disponibile, se non riesce a soddisfare una richiesta restituisce un codice di errore. È quindi sufficiente presentare una richiesta per l’intera memoria indirizzabile FFFFH paragrafi, che ovviamente non può essere soddisfatta, per avere in BX il numero dei MS-DOS um 87 di 138 paragrafi non ancora allocati. FUNZIONE 48H Descrizione Categoria Input Output ALLOCATED MEMORY Alloca memoria. Gestione memoria. AX = 48H BX = numero dei paragrafi o blocchi di memoria richiesti. AX = pointer al segmento iniziale del blocco allocato. BX = dimensione del maggiore dei blocchi a disposizione. FUNZIONE 49H Descrizione Categoria Input RELEASE ALLOCATED MEMORY Rilascia memoria. Gestione memoria. AX = 49H ES = pointer al segmento da rilasciare. FUNZIONE 4AH Descrizione Categoria Input MODIFY ALLOCATED MEMORY (SET BLOCK) Modifica la memoria allocata. Gestione memoria. AX = 4AH ES = pointer al segmento che va modificato BX = nuova dimensione richiesta. BX = numero massimo di blocchi liberi. Output File MEMTEST.ASM Serve a dimostrare praticamente il funzionamento delle funzioni di allocazione memoria; controlla lo spazio a disposizione, dopodiché riduce la memoria a propria disposizione a 100H 256 paragrafi, 4 KB, inizia quindi a richiedere ciclicamente blocchi di 1000H 4096 paragrafi, 64 KB alla volta, presentando sullo schermo il pointer all’area di volta in volta allocata. L’esecuzione dell’applicazione s’interrompe quando un errore segnala che non vi è più memoria disponibile. Normalmente quando un’applicazione è caricata le è allocata tutta la memoria disponibile, spetta all’applicazione stessa ridurre autonomamente la memoria che le è stata assegnata e restituire un certo numero di paragrafi al SO, se questo procedimento può non avere importanza in sistemi sui quali è eseguita una sola applicazione alla volta, in sistemi multitasking è molto importante che i processi rinuncino a possedere memoria della quale non hanno bisogno. STACKSEG SEGMENT PARA STACK ‘STACK’ DB 200H DUP (?) STACKSEG ENDS DISP_STRING MACRO STR ;presentazione stringa sul video MOV AX,SEG STR MOV DS,AX MOV DX,OFFSET STR ;DS:DX punta a STR MOV AH,09H INT 21H ENDM CONV_TO_ASCII MACRO INP_BYTE ;conversione in ascii del byte d’ingresso LOCAL CONT_1,CONT_2 ;risultato in AX MOV AL,INP_BYTE MOV AH,INP_BYTE AND AL,0FH ;mascheramento parte superiore ADD AL,30H ;conversione ascii CMP AL,39H ;char <=9? MS-DOS um 88 di 138 JBE CONT_1 ;char ascii tra 0..9 ADD AL,7H ;char ascii tra A..F CONT_1: AND AH,0F0H ;mascheramento parte inferiore MOV CL,4H ;spostamento a destra del SHR AH,CL ;char in AH ADD AH,30H CMP AH,39H JBE CONT_2 ADD AH,7H CONT_2: NOP ENDM DISP_RESULT MACRO STR,RES ;presentazione di una parola come risultato in STR[28] MOV BX,RES PUSH BX CONV_TO_ASCII BH MOV STR[28],AH ;primo char in STR MOV STR[29],AL ;secondo char in STR POP BX CONV_TO_ASCII BL MOV STR[30],AH ;terzo char in STR MOV STR[31],AL ;quarto char in STR DISP_STRING STR ENDM DATA SEGMENT WORD ‘DATA’ OUTSTR DB “PROGRAMMA MEMTEST CONTROLLO MEMORIA “,13,10,”$” MSG1 DB “NUMERO DI BLOCCHI RICHIESTI: “,13,10,”$” MSG2 DB “NUMERO BLOCCHI DISPONIBILI: “,13,10,”$” MSG3 DB “RIDUZIONE A BLOCCHI: “,13,10,”$” MSG4 DB “INDIRIZZO SEGMENTO (DA AX ): “,13,10,”$” ERR_7 DB “ERRORE (7) NEI BLOCCHI DI CONTROLLO “,13,10,”$” ERR_8 DB “ERRORE (8) MEMORIA INSUFFICIENTE “,13,10,”$” ERR_9 DB “ERRORE (9) SEGMENTO ERRATO “,13,10,”$” REQ_M DW 0 ;memoria richiesta FREE_M DW 0 ;memoria disponibile NEW_S DW 0 ;pointer ad un nuovo segmento DATA ENDS CSEG SEGMENT WORD ‘CSEG’ ASSUME CS:CSEG,DS:DATA,SS:STACKSEG BEGIN: MOV BX,DATA MOV DS,BX DISP_STRING OUTSTR CHECK_MEMORY: ;controllo memoria disponibile MOV REQ_M,0FFFFH ;prima richiesta di memoria DISP_RESULT MSG1,REQ_M MOV AH,4AH ;funzione dos set_block ES punta al PSP di MEMTEST MOV BX,REQ_M ;BX = numero di blocchi INT 21H MOV FREE_M,BX ;memoria libera in BX DISP_RESULT MSG2,FREE_M ;presentazione primo risultato REDUCE_MEMORY: ;riduzione con set_block della memoria allocata MS-DOS um 89 di 138 MOV REQ_M,100H DISP_RESULT MSG3,REQ_M MOV AH,4AH MOV BX,REQ_M INT 21H JNC REQUEST_MEMORY JMP SHOW_ERROR REQUEST_MEMORY: MOV REQ_M,1000H DISP_RESULT MSG1,REQ_M MOV AH,48H MOV BX,REQ_M INT 21H JC SHOW_ERROR MOV NEW_S,AX DISP_RESULT MSG4,NEW_S JMP REQUEST_MEMORY disponibile SHOW_ERROR: CMP AX,7 JNE ERROR_8 DISP_STRING ERR_7 JMP END_PROCESS ERROR_8: CMP AX,8 JNE ERROR_9 DISP_STRING ERR_8 JMP END_PROCESS ERROR_9: DISP_STRING ERR_9 END_PROCESS: MOV AL,0 MOV AH,4CH INT 21H CSEG ENDS END BEGIN MS-DOS ;256 paragrafi = 4Kbyte ;continuazione se non ci sono errori nel CF = 0 ;richiesta nuovo blocco di memoria ;4096 paragrafi = 64Kbyte ;funzione dos allocate_memory ;BX = numeri di blocchi ;uscita in caso di errore CF = 1 ;AX = indirizzo segmento libero ;presentazione segmento ;il ciclo procede fino a quando c’è memoria ;presentazione casi di errore ;AX = codice di errore ;errore nei blocchi controllo ;memoria insufficiente ;segmento errato um 90 di 138 Si può vedere chiaramente che i pointer alle aree assegnate si trovano precisamente a 1001H paragrafi di distanza, dove il paragrafo aggiuntivo è quello contenente l’MCB. MS-DOS um 91 di 138 FILE SYSTEM Introduzione La versione originale 1.0 di MS-DOS fu modellata a somiglianza del CP/M, che comprendeva una sola cartella e l’uso di FCB (File Control Block), blocchi di controllo per effettuare l’I/O e sono state mantenute nelle versioni successive per motivi di compatibilità. La versione 2.0 aveva in più un file system gerarchico con i descrittori di file e le chiamate di sistema, erano usate come in Unix. Le chiamate usate dal CP/M non furono più usate ed erano considerate obsolete; le nuove applicazioni scritte in questa versione non potevano più utilizzarle. Dalla versione due sono disponibili nuove funzioni generiche d’I/O basate su handle (identificatori) dei file, tecnica più moderna che riproduce il metodo usato da Unix. L’handle di un file è una word, 16 bit, contenente un numero unico che serve da identificatore. Per creare oppure aprire un file, un’applicazione passa a MS-DOS un pathname e un attributo da assegnare al file stesso. MS-DOS associa ad esso un handle usato per tutte le successive manipolazioni del file, che ha il primo numero libero, normalmente si possono aprire fino ad un massimo di N handle, di cui i primi 5 sono predefiniti. Tutti i parametri di servizio relativi al file posizione fisica, modo di accesso, protezioni, sono registrati in una struttura dati riservata; le operazioni sul file fanno riferimento a questa struttura tramite l’handle. Una novità derivata da Unix è il trattare periferiche d’I/O come se fossero file sequenziali. In MS-DOS sono predefiniti 5 di tali file; essi sono sempre aperti e associati ai seguenti handle. 0 standard input, tastiera, può essere ridirezionato da (<). 1 standard output, schermo, può essere ridirezionato da (>). 2 standard error, è sempre lo schermo. 3 AUX uscita ausiliaria. 4 PRN stampante. Punti di paragone tra il file system di MS-DOS e quello di Unix. CARATTERISTICHE Sistema con directory gerarchiche. Directory corrente. Pathname assoluti e relativi. Directory (.) e (..) File speciali a caratteri. File speciali a blocchi. Lunghezza dei nomi dei file. Separatore nei nomi. “a” equivale ad “A”. Proprietari, gruppi, protezione. Concatenazioni (link). File system montati. Attributi di file. Unix Si Si Si Si Si Si 14 o 255 / No Si Si Si No MS-DOS Si Si Si Si Si Si 8+3 \ Si No No No Si Entrambi i sistemi permettono alla cartella radice di avere delle sotto cartelle e ognuna di queste può avere a sua volta altre sotto cartelle arrivando ad un livello qualsiasi; in entrambe sussiste il concetto di cartella di lavoro, i pathname relativi e quelli assoluti. MS-DOS um 92 di 138 Entrambi i sistemi usano i nomi (.) e (..) per la cartella corrente e per quella genitore e supportano file speciali di caratteri per terminali, stampanti e altri dispositivi seriali e i file speciali di blocchi per i dischi. Nonostante queste affinità, tra i due sistemi ci sono, comunque, delle differenze. I nomi dei file di Unix sono di 14 o 255 caratteri, a seconda della versione in uso, i nomi dei file MS-DOS hanno una parte di base di 8 caratteri, seguita opzionalmente da un’estensione che inizia sempre con un punto e contiene da 1 a 3 caratteri. BAT, file batch. SYS, driver di dispositivo. COM, file binario eseguibile formato da un solo segmento. EXE, file binario eseguibile formato da più segmenti con intestazione. OBJ, file oggetto prodotto da un compilatore. TXT, file testo in formato ASCII. DOC, file documento realizzato con un word processor. In entrambi i casi, i nomi dei file sono formati da qualsiasi carattere legale. Un’altra differenza per chi usa entrambi i sistemi è l’uso di (/) come componente separatore in Unix e l’uso di (\) per la stessa funzione in MS-DOS. La ragione di questa differenza è collegata all’utilizzo iniziale di MS-DOS di (/x) al posto di (- x) nella shell per passare il flag (x) ad un’applicazione, un altro fossile del CP/M. Poiché i flag sono analizzati dall’applicazione stessa, non solo dalla shell, alcune applicazioni lo fanno secondo il metodo Unix. Un’altra differenza è che per la shell di Unix “ABC”, “Abc” e “abc” sono file che non hanno alcuna relazione tra loro; per la shell di MS-DOS, invece, rappresentano lo stesso file, inoltre, in Unix ci sono proprietari, gruppi, protezione e file system montati mentre niente di tutto ciò è presente in MS-DOS. Una caratteristica che ha MS-DOS è la presenza di solo 4 attributi. 1. Readonly, il file non può essere modificato. 2. Archive, il file è stato modificato nell’ultima archiviazione. 3. System, il file system non può essere cancellato dal comando DEL. 4. Hidden, il file non è elencato dal comando DIR. Il supportare molteplici dischi ma non avere l’operazione di mount crea un problema: come fa il sistema a sapere su quale disco si trova il file? È necessario fornire, oltre al nome del file, il nome del dispositivo, (A:) per il primo floppy, (B:) per il secondo e (C:) per il primo hard disk. chiamate di sistema Le chiamate CREATE, OPEN, CLOSE, READ e WRITE in C hanno le stesse funzioni di quelle di Unix; le differenze sono le seguenti. 1. Qualcuno decise di scrivere in questo caso CREATE con la “E”. 2. Al posto della modalità di protezione sono forniti i 4 bit di attributi. Infatti, la chiamata successiva è LSEEK, leggermente mascherata dalla divisione dell’offset del file in due word al posto di passarlo come un tutt’uno sebbene le librerie d’interfaccia del C ne accettino uno completo e poi lo convertano in due più corti. Le operazioni di rename e delete in C sono ovvie e in Unix corrispondono alle chiamate rename e unlink, rispettivamente. La chiamata get/set date/time in C non è realmente una chiamata di sistema. La chiamata di sistema attuale prende la data e l’ora e la inserisce in registri differenti; poiché le funzioni C non possono accettare come risultato due valori, la maggior parte delle librerie e il compilatore dividono queste chiamate in due funzioni. L’altra, non mostrata, prende l’ora in cui il file è stato modificato l’ultima volta; si noti che queste chiamate sono necessarie poiché non esiste una chiamata STAT. La chiamata get current directory in C è identica a quella in Unix, tranne per il fatto che specifica quale dispositivo è coinvolto; in Unix ciò non è necessario. MS-DOS um 93 di 138 FUNZIONE 3CH Descrizione Categoria Input Output FUNZIONE 3DH Descrizione Categoria Input Output CREATE A FILE Crea un nuovo file, se esiste già è aperto con lunghezza zero, in ogni caso il file è aperto in read/write. I/O su dischi. AH = 3CH CX = attributi per il file DS:DX = pointer al pathname. Attributi file: 00 = normal 01 = read-only 02 = hidden 04 = system Se (CF = 0) allora AX = file handle, altrimenti AX = codice di errore. Codice di errore: 3 = pathname non trovato 4 = nessun file handle disponibile 5 = accesso negato, esempio Read-only OPEN A FILE Apre il file specificato con un prestabilito codice di accesso. I/O su dischi. AH = 3DH AL = codice di accesso DS:DX = pointer al pathname. Codice di accesso: 76543210 AAA modo di accesso: 210 000 read-only 001 write-only 010 read-write R riservato sempre zero SSS modo condiviso (share) I ereditarietà, solitamente 1. Quando il file non è condiviso da più processi, porre SSS a 000. Se (CF = 0) allora AX = file handle, altrimenti AX = codice di errore. Codice di errore: 1 = numero di funzione non valido 2 = file non trovato 3 = pathname non trovato 4 = nessun file handle disponibile 5 = accesso negato, esempio Read-only 12 = codice di accesso non valido. FUNZIONE 3EH Descrizione Categoria Input Output CLOSE A FILE HANDLE Chiude il file handle corrente. I/O su dischi. AH = 3EH BX = file handle. Se (CF = 0) allora AX = indefinito, altrimenti AX = codice di errore. Codice di errore: 6 = file handle invalido. FUNZIONE 3FH Descrizione READ FROM FILE OR DEVICE, USING A HANDLE Legge uno specificato numero di byte, da un file o da un dispositivo e li memorizza in un buffer di memoria, la lettura inizia dal valore corrente del file pointer. I/O su dischi. AH = 3FH BX = file handle CX = numero di byte da leggere DS:DX = pointer al buffer di memoria. Se (CF = 0) allora AX = byte letti, altrimenti AX = codice di errore. Codice di errore: 5 = accesso negato, esempio Read-only 6 = file handle non valido. Categoria Input Output MS-DOS um 94 di 138 La funzione inizia a leggere i byte del file, a partire dal valore corrente del file pointer. Terminata la lettura, il file pointer è incrementato del numero di byte letti e la funzione ritorna con CF = 0, l’operazione di lettura ha avuto successo e AX riporta il numero di byte letti. È conveniente effettuare un controllo tra il numero di byte da leggere, specificati in CX e quelli effettivamente letti il cui numero è riportato in AX, nel caso in cui AX risulti minore di CX il file pointer è arrivato alla fine del file, oppure si è verificato un errore. La funzione può essere usata per leggere i caratteri provenienti dalla tastiera, file handle uguale a 0 o dalla linea seriale, file handle uguale a 3. FUNZIONE 40H Descrizione WRITE TO FILE OR DEVICE, USING A HANDLE Scrive uno specificato numero di byte, prelevati da un buffer di memoria, in un file o in un dispositivo, la scrittura inizia a partire dal valore corrente del file pointer. Categoria I/O su dischi. Input AH = 40H BX = file handle CX = numero di byte da scrivere DS:DX = pointer al buffer di memoria. Output Se (CF = 0) allora AX = byte scritti, altrimenti AX = codice di errore. Codice di errore: 5 = accesso negato, esempio Read-only 6 = file handle non valido. Terminata l’operazione di scrittura il file pointer è aumentato del numero di byte scritti. Se la funzione ritorna con CF uguale a 0, l’operazione ha avuto successo e AX riporta il numero di byte scritti. Se il disco è pieno, è probabile che nel file siano scritti un numero minore di byte rispetto a quelli indicati da CX. In questo caso la funzione ritorna senza codice di errore, ma AX indica il numero di byte effettivamente scritti. È conveniente confrontare, al termine della funzione, AX con CX per rilevare eventuali perdite di dati dovute al disco pieno. FUNZIONE 42H Descrizione MOVE FILE POINTER Sposta il file pointer all’interno di un file di un numero di byte, può essere spostato dall’inizio, dalla fine o dalla posizione corrente. Categoria I/O su dischi. Input AH = 42H AL = modo di spostamento BX = file handle CX:DX = offset (in byte) a 32 bit con segno. Modo di spostamento: 0 muove a partire dall’inizio del file 1 muove a partire dal valore corrente 2 muove a partire dalla fine del file Output Se (CF = 0) allora DX:AX = nuovo file pointer, altrimenti AX = cod. err. Codice di errore: 1 = modo di spostamento non valido 6 = file handle non valido. La funzione aggiorna il file pointer sommandogli il numero con segno a 32 bit specificato in CX:DX. È possibile spostare il file pointer sia prima dell’inizio del file sia dopo la fine. In ogni caso, un’operazione di questo tipo causerà un errore in una successiva funzione di scrittura o lettura del file. È possibile determinare la lunghezza del file, utilizzando il modo 2 di spostamento con CX:DX = 0. Il nuovo file pointer riportato in DX:AX indica la lunghezza del file. Posizionando il file pointer alla fine del file ed eseguendo successivamente un’operazione di scrittura è possibile aumentare la lunghezza del file. MS-DOS um 95 di 138 FUNZIONE 43H GET OR SET FILE ATTRIBUTES Descrizione Permette di ottenere o di settare gli attributi di uno specifico file. Categoria I/O su dischi. Per ottenere gli attributi. Input AH = 43H AL = 00H DS:DX = pointer al pathname. Output Se (CF = 0) allora CX = attributi file, altrimenti AX = codice di errore. Per settare gli attributi. Input AH = 43H AL = 1 CX = attributi DS:DX = pointer al pathname. Output Se (CF = 0) allora successo, altrimenti AX = codice di errore. Codice di errore: 1 = codice di funzione non valido 2 = file non trovato 3 = percorso non trovato 4 = accesso negato. FUNZIONE 5BH Descrizione Categoria Input Output 39h 3Ah 3Bh 41h 43h 45h 46h 47h 4Eh 4Fh 56h 57h 5Ah CREATE NEW FILE Crea un nuovo file, solo se non già esistente. I/O su dischi. AH = 5BH CX = attributi del file DS:DX = pointer al pathname Se (CF = 0) allora AX = file handle, altrimenti AX = codice di errore. Codice di errore: 3 = percorso non trovato 4 = nessun file handle disponibile 5 = accesso negato 80 = file già esistente. Create Directory. Remove Directory. Change Current Directory. Delete Directory Entry. Get/Set File Attributes. Duplicate File Handle. Force Duplicate File Handle. Get Current Directory. Find First File. Find Next File. Change Directory Entry. Get/Set Date/Time of File. Create Temporary File. implementazione S’inizierà a descrivere il file system di MS-DOS guardando prima lo schema di un disco. Lo schema di un hard disk e gli schemi dei floppy sono diversi tra loro; si parlerà in particolare dell’hard disk. Tutti i dischi rigidi hanno lo stesso schema. Il settore di boot contiene l’informazione critica sul file system, ovvero il codice per far partire il sistema; seguono delle tabelle che tengono traccia di tutto lo spazio del disco, poi c’è la root e quindi tutto il resto. Il settore di boot inizia sempre con un’istruzione JUMP che tralascia l’informazione descrittiva del settore e va all’inizio del codice. In questo modo la ROM può iniziare il boot leggendo il settore di boot nella memoria, avviandolo senza doversi preoccupare dello schema interno. Segue una lista di parametri critici, ivi incluso il numero di byte per settore, il numero di settori per blocco, il numero di tabelle di allocazione dei file, la dimensione della directory root, la dimensione del dispositivo e altri dati del genere. MS-DOS um 96 di 138 Dopo questi parametri c’è il codice di bootstrap. A differenza del bootstrap di ROM che legge semplicemente il settore 0 e gli trasferisce il controllo, questo codice sa che sta facendo il boot di MS-DOS. Infatti, il codice di ROM può fare indifferentemente il boot di Unix o di qualsiasi altro SO. Il codice del settore di boot localizza la directory radice e cerca IO.SYS e MSDOS.SYS; a questo punto usa BIOS per caricarli e posizionarsi all’inizio di IO.SYS. Il settore di boot contiene, nella parte finale, la tabella delle partizioni i cui elementi indicano l’inizio e la fine di ogni partizione, fino ad un massimo di 4; ogni partizione può contenere un file system differente, per cui MS-DOS e Unix possono coesistere senza problemi sullo stesso hard disk, ognuno nella sua partizione. Una partizione può essere marcata come attiva, per permettere che solo quella inizi a girare quando è fatto il boot del sistema dal disco rigido. L’utility FDISK, serve per permettere agli utenti di creare, cancellare e modificare le dimensioni delle partizioni. Una volta che un disco è stato diviso in partizioni e i file system sono stati sistemati in ognuna di esse, una nuova ripartizione del disco comporta quasi sempre lo smantellamento di tutti i file system e il loro ripristino. Per i floppy invece si parla di cluster, gruppo, blocco, grappolo; è un insieme di settori consecutivi, record fisico, la cui dimensione, in numero pari a una potenza di due, è stabilito al momento della formattazione. Esempio. Cluster = 1024 byte (1KB) = 2 settori 9 settori = 9 X 512 = 4608 byte 40 tracce = 40 X 4608 = 184320 byte 2 facce = 2 X 184320 = 368640 : 1024 = 360 KB La capacità logica è solamente di 354 KB, ne mancano 6, 6144 byte, 12 settori, 1 traccia più 1/3, MS-DOS occupa 6 cluster numerati da 1 a 6 per i descrittori e 354 numerati da 7 a 360 per i dati. Per sicurezza e integrità, esistono due copie della FAT costantemente aggiornate. Il primo byte della FAT usato dal device driver per identificare il disco. La mappa dell’area dati del disco comincia al byte di offset quattro. Dopo il settore di boot si trova la FAT che tiene traccia di tutto lo spazio del disco. Questa tabella, in MS-DOS, ha le stesse prestazioni della lista libera e della tabella degli inode in Unix. MS-DOS um 97 di 138 Per fornire maggiore affidabilità, si duplica la FAT, così il sistema non sarà distrutto se la FAT principale diventa illeggibile, la FAT contiene un elemento per ogni cluster sul disco. La dimensione del cluster si trova nel settore di boot e può variare da 1 settore per il disco RAM, fino a 8 settori per gli hard disk di grandi dimensioni. Nella versione 1.0, la dimensione dell’elemento di FAT era di 12 bit, ma poiché questa dimensione può gestire solo dischi fino a 4096 cluster, quando furono messi in circolazione dischi rigidi più grandi, essa fu modificata a 16 bit, permettendo così 65536X512 = 33 MB. Le partizioni più grandi di 33 MB sono gestite tramite l’utilizzo di dimensioni del cluster maggiori dei 512 byte standard, blocchi di 2 KB per i dischi da 100 MB. Lo schema della FAT è mostrato nella figura seguente, lo schema reale è diverso poiché i campi sono codificati in uno strano modo, un ritorno alle radici CP/M di MS-DOS. Vi è una corrispondenza biunivoca tra gli elementi della FAT e i cluster del disco, fatta eccezione per i primi due elementi che codificano la classe del disco. In questo esempio è mostrato un file che inizia al cluster 6 e l’elemento della FAT in posizione 6 contiene 8, a significare che il secondo cluster del file è il cluster 8; l’elemento della FAT in posizione 8 contiene 4, per cui il cluster successivo è il cluster 4; l’elemento della FAT in posizione 4 è 2 e infine l’elemento in posizione 2 è un codice speciale che indica la fine del file. Così, dando il numero del primo cluster di un file è possibile localizzare tutti i cluster seguendo la catena nella FAT. L’elemento della cartella relativo ad un file contiene il cluster di partenza e la FAT fornisce la parte rimanente della catena. I cluster liberi sono marcati da un altro codice speciale nella FAT. Quando un file aumenta la sua dimensione, MS-DOS cerca un elemento libero nella FAT e assegna quel cluster al file; allo stesso modo è usato un codice diverso per marcare i cluster non leggibili. Significato dei valori assunti dalle entry nella FAT. 0000H cluster non occupato e disponibile. FFF7H cluster danneggiato. FFFFH EOF (End Of File), ultimo cluster di un file. Per vedere com’è integrata la FAT nel sistema, si descrive ora una chiamata di sistema OPEN dall’inizio alla fine. Essa parte quando MS-DOS esamina la tabella dei descrittori del file, tenuta nel PSP come un array di 20 byte e cerca un descrittore di file libero. Ognuno dei byte della tabella dei descrittori dei file contiene sia un indice alla tabella principale del file system approssimativamente analoga alla tabella degli i-node di Unix, MS-DOS um 98 di 138 oppure un codice che informa che il descrittore del file non è in uso; se è trovato un descrittore di file libero, si cerca uno spazio libero nella tabella del file system. Se c’è, allora è esaminato il pathname del file da aprire per controllare se esso è un CON, un LPT o il nome di uno degli altri file speciali; durante questo confronto sono ignorate sia le cartelle sia l’estensione. Se esso non è un file speciale, si fa un controllo sul primo carattere per vedere se è una (\), in questo caso il path è assoluto e la ricerca inizia nella root; in caso contrario, il path è relativo e la ricerca inizia nella cartella di lavoro. Da questo punto di vista MS-DOS è sostanzialmente lo stesso di Unix. Una cartella in MS-DOS ha un elemento di 32 byte per ogni file o directory. I primi 11 caratteri contengono il nome del file e l’estensione. A differenza di Unix, il punto che separa la parte principale del nome dall’estensione non è memorizzato esplicitamente nella directory. Esempio, entry per i floppy da 360 KB = 112; da 1.44 MB = 224. FILENAME (0..7) Nome del file, 8 caratteri allineati a sinistra e completati eventualmente da spazi. Il primo byte indica lo stato del file. 1. 00H la entry non è mai stata usata, questa informazione è usata per limitare le ricerche nella cartella. 2. 05H il vero primo carattere del nome E5H, indica che il file è stato cancellato. Infatti MS-DOS non cancella fisicamente un file, ma si limita a sostituire il primo carattere del nome con E5H e a liberare, nella FAT, i cluster occupati; di conseguenza, poiché, all’interno della directory sono mantenute inalterate tutte le altre informazioni, sarà possibile, a patto di non aver occupato lo spazio per un altro file, recuperare le informazioni contenute nel file cancellato con il comando UNDELETE. 3. 2EH la entry corrisponde a una sotto cartella, se anche il secondo byte è 2EH, allora il campo 26-27 contiene il numero di cluster della directory padre, o 0000H se la directory padre è root, altrimenti, i byte da 01 a 10 contengono spazi e il campo 26-27 contiene il numero di cluster di questa stessa cartella. 4. E5H il file è stato cancellato, ogni altro carattere è il carattere del nome di un file. 5. . elemento autoreferente il cui numero di cluster iniziale punta alla cartella corrente. 6. .. elemento padre il numero di cluster iniziale si riferisce all’inizio della cartella padre. ESTENSIONE (8-10) Estensione del nome del file. MS-DOS um 99 di 138 ATTRIBUTI (11) Contengono i seguenti codici. 1. 00H bit di normale, il file può essere letto e scritto senza limitazioni. 2. 01H bit di readonly, 1 per i file di sola lettura, non si può scrivere sul file. 3. 02H bit di hidden, 1 per i file nascosti, non elencati da DIR. 4. 04H bit di sistema, 1 per i file di sistema, non cancellabili. 5. 08H bit di volume, label associata al disco, 1 per indicare che l’elemento si riferisce all’etichetta di volume, solo un file può avere questo attributo e deve essere nella directory radice. 6. 10H bit di directory, 1 per indicare che l’elemento si riferisce ad una cartella. 7. 20H bit di archivio, 1 quando è modificato il file, 0 quando è salvato. Il byte di attributo si può leggere o scrivere usando le chiamate di sistema. RISERVATI (12-21) Per uso futuro. ORA (22-23) Ora di creazione o di ultimo aggiornamento, secondo la seguente mappa di bit (B7 - B0). Offset 17H: H H H H M M M. Offset 18H: M S S S S S S. H: il numero binario, 4 bit, che rappresenta le ore (0-23). M: il numero binario, 4 bit, che rappresenta i minuti (0-59). S: il numero binario, 6 bit, che rappresenta i secondi (solo pari). DATA (24-25) Data di creazione o aggiornamento, l’anno, il mese e il giorno sono mappati su due byte. Offset 19H: Y Y Y Y Y Y Y M. Offset 18H: M M M D D D D D. Y: anno, 7 bit, compreso tra 0 e 119 (1980-2099). M: mese, 4 bit, tra 1 e 12. D: giorno, 5 bit, tra 1 e 31. CLUSTER INIZIALE (26-27) Cluster iniziale, è il numero del primo cluster nel file, per primo il byte meno significativo. Permette di localizzare l’inizio della catena nella FAT, rendendo così possibile trovare tutti i cluster successivi. DIMENSIONE (28-31) Dimensione del file in byte, con prima la word meno significativa. È interessante confrontare l’implementazione del file system MS-DOS con quella di Unix; in quest’ultimo un elemento di directory contiene il nome del file e il numero dell’i-node e nient’altro; tutte le altre informazioni, come la dimensione del file, l’ora e il giorno di creazione e i numeri di cluster sono negli i-node. MS-DOS non ha gli i-node per cui tutte le informazioni sono contenute nell’elemento della directory, questo rende impossibili i link poiché avere due elementi di directory che contengono lo stesso numero di cluster iniziale non può funzionare; ognuno avrebbe il suo giorno, ora e dimensione del file provocando inconsistenze. Ciò significa anche che l’accesso diretto ad un cluster vicino alla fine di un grosso field richiede uno o più accessi al disco. Ritornando alla chiamata di sistema OPEN, se la ricerca ha successo, l’elemento di directory è copiato nella tabella dei file del sistema, che ha un elemento per ogni file aperto; il campo posizione del file è quindi messo a 0. L’avere il campo posizione del file sistemato qui non provoca problemi come MS-DOS um 100 di 138 succederebbe in Unix poiché non c’è il pericolo che un utente indipendente possa aprire il file; infatti il descrittore di file è restituito al chiamante e la OPEN termina. Con questa impostazione di base, l’implementazione della READ e della WRITE è semplice. Il sistema usa il descrittore del file per accedere all’array di 20 byte contenuto nel PSP per ottenere l’indirizzo della tabella di sistema dei file che contiene le informazioni riguardanti il file, queste informazioni comprendono l’inizio della catena dei cluster del disco, la posizione corrente del file, la dimensione corrente, che tutte insieme permettono l’esecuzione delle operazioni. La dimensione della tabella di sistema dei file è determinata da una riga in CONFIG.SYS, ma è limitata a non più di 256 dall’uso di elementi di un byte nel PSP. File FILETYPE.ASM Riproduce le funzioni del comando TYPE. Legge dalla linea di comando il nome del file da visualizzare, lo apre, ne legge blocchi di carattere lunghi buf_len byte e li carica nel buffer out_buf che in seguito è passato al modulo di scrittura su file logico di uscita, predefinito con handle uguale ad un’unità schermo. Non ha luogo alcun controllo del tipo di caratteri che sono direttamente copiati così come provengono dal file d’input. Un controllo sul numero dei byte letti indica quando il file è giunto al suo termine, nel qual caso l’esecuzione salta al modulo di chiusura del file close_file_handle. Quindi chiude il file e termina l’esecuzione; mostra anche come avviene la lettura dei parametri passati insieme al comando, interessante pure la ridirezione d’I/O. STACKSEG SEGMENT PARA STACK ‘STACK’ DB 200H DUP (?) STACKSEG ENDS CSEG SEGMENT WORD ‘CSEG’ ASSUME CS:CSEG,DS:CSEG,ES:CSEG BUF_LEN EQU 80 ;legge dal file d’ingresso blocchi lunghi BUF_LEN byte OUT_HANDLE EQU 1 ;handle di output = display OUTSTR DB “PROGRAMMA PER TYPE DI FILE “,13,10,”$” FILE_NAME DB 32 DUP(0) FILE_HANDLE DW 0 ;handle di input OUT_BUF DB BUF_LEN DUP (0) ;questi blocchi sono caricati in BUF_LEN per andare al file logico d’uscita senza nessun controllo LOCAL_PSP DW 0 ;prima del run DS ed ES puntano al PSP FILETYPE ;salva questo valore BEGIN: MOV CS:LOCAL_PSP,DS ;il PSP è contenuto in DS MOV AX,CSEG ;DS = CSEG via AX MOV DS,AX MOV DX,OFFSET OUTSTR ;DS:DX punta ad OUTSTR MOV AH,09H INT 21H GET_FILE_NAME: ;legge dalla linea di comando filename e copy in FILE_NAME eliminando i blank CLD ;SI e DI vanno incrementati MOV DI,OFFSET FILE_NAME ;indirizzo di destinazione MOV AX,CSEG ;ES = CSEG via AX MOV ES,AX ;ES:DI punta a FILE_NAME MOV DS,LOCAL_PSP ;DS:DI punta alla stringa di comando MOV SI,80H LODSB ;lunghezza della stringa in AL MS-DOS um 101 di 138 XOR AH,AH MOV CX,AX LOOP_1: LODSB CMP AL,32 JA COPY_INP_STRING DEC CX JMP LOOP_1 COPY_INP_STRING: STOSB DEC CX REP MOVSB OPEN_FILE_HANDLE: MOV AX,CSEG MOV DS,AX MOV DX,OFFSET FILE_NAME MOV AH,3DH MOV AL,0H INT 21H JC END_PROCESS MOV FILE_HANDLE,AX READ_BLOCK: MOV DX,OFFSET OUT_BUF MOV CX,BUF_LEN MOV BX,FILE_HANDLE MOV AH,3FH INT 21H JC END_PROCESS DISPLAY_ON_OUTPUT: CMP AX,0 JE CLOSE_FILE_HANDLE MOV CX,AX MOV BX,OUT_HANDLE MOV DX,OFFSET OUT_BUF MOV AH,40H INT 21H JMP READ_BLOCK CLOSE_FILE_HANDLE: MOV BX,FILE_HANDLE MOV AH,3EH INT 21H END_PROCESS: MOV AL,0 MOV AH,4CH INT 21H CSEG ENDS END BEGIN MS-DOS ;CX = numero di byte da leggere ;delete blank dalla stringa d’ingresso ;controllo ASCII = 32 ;byte da leggere -1 ;lettura stringa d’ingresso ;ES:DI punta già a FILE_NAME ;copiatura byte successivi, numero ;contenuto in CX ;apertura file in lettura ;DS:DX punta a FILE_NAME ;funzione DOS open_file ;accesso: read_only ;end per errore carry true ;risultato chiamato da AX,handle per il file ;lettura file ;DS:DX punta ad OUT_BUF dove metto i char ;CX = numero di byte da leggere ;BX = file handle ;funzione DOS read_file ;end per errore carry true ;su video il contenuto di OUT_BUF ;AX = numero di byte scritti ;AX = 0 a fine file ;CX = numero di byte in uscita ;BX = handle file logico output ;DS:DX punta ad OUT_BUF ;funzione DOS write_file ;lettura di un nuovo blocco ;BX = file handle ;funzione DOS close_file um 102 di 138 I/O Introduzione MS-DOS supporta i file speciali di caratteri per fare l’I/O sui dispositivi seriali, per lo più come fa Unix, tranne per il fatto che i nomi dei dispositivi non sono memorizzati in una directory come /dev. Per copiare un file su una console, video, si può usare il comando: COPY FILE CON. Il file CON può essere aperto anche dalle applicazioni, per lo più come /dev/tty può essere aperto dai programmi Unix, infatti, può essere aperto come \DEV\CON anche se non c’è la cartella \DEV. L’apertura di un file di caratteri speciali restituisce un descrittore di file, che può essere usato per la lettura e la scrittura, altri file di caratteri speciali comprendono COM la prima porta seriale, LPT1 la prima porta di stampante in linea parallela e NUL che ha una funzione identica a quella di /dev/null in Unix. Questi nomi non possono essere usati come la prima parte di qualsiasi nome di file, indipendentemente da quale tipo di estensione essi abbiano. I file di caratteri speciali supportano le modalità cooked e raw, come i file di Unix; in modalità cooked, l’editing tra le linee, come la cancellazione di caratteri è fatta dal SO, rendendo disponibile all’applicazione solo il risultato finale. In modalità raw, i caratteri sono passati all’applicazione esattamente come sono ricevuti; gli editor di video e altre applicazioni interattive operano spesso in questo modo. A differenza di Unix, in cui un processo parte con tre file speciali già aperti, lo standard input, lo standard output e lo standard error, tutti connessi al terminale, in MS-DOS quando parte un processo, esso ha cinque file aperti automaticamente: lo standard input, lo standard output, lo standard error, la linea seriale e la stampante, che usano i descrittori di file rispettivamente da 0 a 4. MS-DOS permette agli utenti d’installare i loro driver di dispositivo solo dopo che il sistema è inizializzato. Tutto ciò è in contrasto con l’approccio Unix, in cui i driver di dispositivo sono compilati sempre nel kernel e non sono installabili in un secondo momento. La differenza è dovuta al fatto che storicamente i sistemi Unix sono stati installati e gestiti nei centri di calcolo, dove un amministratore di sistema è sempre disponibile per la compilazione e la generazione del sistema. Un driver di dispositivo è installato aggiungendo una semplice istruzione al file CONFIG.SYS dando il path name del file che contiene il driver. chiamate di sistema La chiamata IOCTL (IO ConTroL) è formata da un numero considerevole di chiamate per la gestione dei file speciali; alcune opzioni permettono alle applicazioni di verificare un descrittore di file per vedere se è un file speciale di caratteri, per mandare i dati di controllo, in pratica la velocità di linea del terminale, per controllare lo stato dell’input e dell’output del dispositivo, per definire le modalità video o altre, per specificare le pagine di codice dei vari linguaggi nazionali, per leggere o scrivere i parametri. implementazione L’I/O in MS-DOS è realizzato completamente attraverso i file speciali a caratteri e a blocchi. I file a caratteri si occupano dei dispositivi che trattano un carattere per volta, come terminali e stampanti, mentre i file a blocchi servono per i dischi. Associato con ogni file speciale c’è un driver di dispositivo, che contiene il codice che MS-DOS um 103 di 138 permette l’I/O. Alcuni driver, come COM1, CON e LPT1, sono standard e sono contenuti in IO.SYS; gli utenti possono caricare altri driver di dispositivo quando si fa il boot del sistema aggiungendo una o più righe in CONFIG.SYS. Avere i driver di dispositivo serve a dotare MS-DOS di un’interfaccia standard per tutti i dispositivi H/W. Quando un’applicazione scrive o legge un file speciale compresi tutti gli accessi al file sytem, MS-DOS chiama il driver corrispondente in modo standardizzato, dicendogli quale di essi vuole, allontanando il SO dai particolari dell’H/W. L’idea di permettere i driver installabili dagli utenti è servita per permettere a chiunque di comprare qualsiasi dispositivo d’I/O per i propri PC, tra cui nastri, sintetizzatori vocali, plotter e strumenti musicali digitali. Per usare uno di questi è necessario creare un nuovo file speciale e installare un nuovo driver che se ne occupa. In Unix, l’installazione di un nuovo driver di dispositivo richiede la ricompilazione del SO, il che è accettabile per l’installazione tradizionale di un computer, ma assolutamente impraticabile per un prodotto di massa come MS-DOS. Un driver può andare bene per un file speciale a caratteri o un file speciale a blocchi, ma non per entrambi, poiché le interfacce dei due tipi sono un po’ differenti e le funzioni che devono adempiere non sono le stesse, l’accesso diretto è permesso sui dispositivi a blocchi, ma non su quelli a carattere. Ogni driver è un programma separato, scritto in linguaggio assembly, in C o un altro linguaggio e compilato, iI driver hanno estensione SYS come MOUSE.SYS per distinguerli dagli altri file. Tutti i driver a caratteri hanno la seguente struttura, i driver a blocchi differiscono non molto da quelli a caratteri. Prima si trova un’intestazione, header, di 18 byte che identifica il driver e descrive alcune delle sue proprietà; segue il codice, formato da due parti, una che accetta le richieste MSDOS e una per realizzare l’I/O. Quando è installato un driver, esso è messo in cima ad una lista concatenata di driver; una variabile interna di MS-DOS contiene il puntatore al primo elemento della lista ed è usata per visitare la lista. Poiché la visita della lista parte dalla testa, un driver appena installato ha la precedenza su quelli installati precedentemente. Per esempio, il driver standard CON non supporta alcuna sequenza di escape per l’output su video, per cui se un utente ne vuole una di tipo ANSI deve inserire in CONFIG.SYS il file ANSI.SYS, che carica un nuovo driver per CON sul disco rigido; da questo momento tutto l’I/O su video sarà mandato ad ANSI.SYS. La parola successiva nell’intestazione è una bit map, parola di attributi, usata per MS-DOS um 104 di 138 distinguere i dispositivi a caratteri da quelli a blocchi e per dire se sono supportate alcune funzioni opzionali. I 5 bit di ordine più basso sono usati per rendere possibile a MS-DOS una ricerca rapida nella lista in modo da trovare il driver della console, del clock, lo standard input e lo standard output senza dover cercare i loro nomi. 15 14 13 11 7 6 4 3 2 1 0 Blocco di carattere. IOCTL è supportato? L’output fino allo stato busy è supportato? L’apertura e la chiusura sono supportate? Le richieste di IOCTL sono supportate? I set/get logical drive sono supportati? 1 se è un driver di console con output veloce. 1 per il driver del clock. 1 per il driver di NULL. 1 per lo standard output. 1 per lo standard input. Le due parole successive danno rispettivamente gli offset del gestore di richieste e il codice d’I/O, infine, si trova il nome del driver, che ha un massimo di 8 caratteri. Quando un file è aperto, MS-DOS prima controlla se il nome appartiene ad un file speciale, visitando la lista dei driver per vedere se il nome del file da aprire corrisponde al nome di qualcuno dei driver nella catena; in questo caso, quel driver è usato per tutte le scritture e le letture fatte sul file. Immediatamente dopo il driver si trova il codice, che è richiamato secondo lo schema che segue. 1. Un’applicazione utente fa una chiamata di sistema READ o WRITE; MS-DOS usa il descrittore del file per localizzare l’elemento della tabella dei file di sistema, guardando nella tabella del descrittore del file del PSP e deduce quale dispositivo deve essere letto o scritto. 2. Forma, poi, un messaggio di richiesta costituito da un’intestazione di 13 byte e, in alcuni casi, da parametri extra; il messaggio contiene il codice di funzione per l’operazione desiderata, l’indirizzo di memoria da cui leggere o scrivere, l’indirizzo del dispositivo per i dispositivi a blocchi e il contatore di byte. 3. MS-DOS, quindi, esamina l’offset della procedura di gestione delle richieste del dispositivo e la chiama; questa procedura esamina il messaggio e salva i campi significativi; poi restituisce il controllo prima che parta il lavoro. 4. Successivamente MS-DOS guarda l’offset del codice d’I/O nell’intestazione del driver di dispositivo e lo chiama per l’elaborazione in corso; la ragione di questa suddivisione in due chiamate non è chiara, ma probabilmente dovrebbe essere di aiuto nel caso in futuro si aggiunga la multiprogrammazione in MS-DOS. 5. Quando il driver ha finito il lavoro, setta una parola di stato che ne indica il successo o il fallimento e restituisce il controllo al chiamante. I driver di dispositivo possono supportare un numero grande di funzioni, sebbene un particolare driver possa indicare che esso non supporta alcune delle più strane; basta mettere a 0 certi bit nella parola di attributi. Se, per esempio, un’applicazione fa una chiamata di sistema IOCTL su un file speciale il cui driver non supporta IOCTL gli è restituito uno stato di errore. I driver non possono usare le chiamate di sistema di MS-DOS perché MS-DOS non è rientrante, in pratica non può accettare una nuova chiamata di sistema mentre è occupato con un’altra. MS-DOS um 105 di 138 COMANDI ATTRIB Visualizza o modifica gli attributi dei file. Questo comando visualizza, imposta o rimuove gli attributi assegnati ai file e alle cartelle, quali l’attributo di sola lettura, di archivio, di file di sistema e di file nascosto. ATTRIB [+R|-R] [+A|-A] [+S|-S] [+H|-H][[unità:][percorso]nomefile] [/S] Opzioni. +R Imposta l’attributo di sola lettura. -R Disattiva l’attributo di sola lettura. +A Imposta l’attributo archivio. -A Disattiva l’attributo archivio. +S Imposta il file come file di sistema. -S Disattiva l’attributo di file di sistema. +H Imposta il file come file nascosto. -H Disattiva l’attributo di file nascosto. /S Elabora i file presenti nella cartella corrente e in tutte le sotto cartelle. Per visualizzare tutti gli attributi di tutti i file presenti nella cartella corrente, utilizzare la seguente sintassi. ATTRIB DISKCOPY Copia il contenuto di un disco floppy nell’unità di origine su un floppy formattato o non formattato inserito nell’unità di destinazione. Il comando DISKCOPY cancella il contenuto del disco di destinazione sovrascrivendovi i nuovi dati; questo comando determina il numero di facce da copiare in base all’unità e al disco di origine. DISKCOPY [unità1: [unità2:]] [/1] [/V] [/M] Opzioni. /V Verifica che le informazioni siano copiate correttamente; l’utilizzo di questa opzione rallenta l’operazione. /M Indica a DISKCOPY di usare solo memoria convenzionale per memorizzazioni provvisorie, DISKCOPY usa di solito il disco rigido per tale operazione, non si debbono scambiare i floppy. CHDIR (CD) Visualizza il nome della cartella corrente oppure cambia la cartella corrente. CHDIR [unità:][path] CHDIR[..] CD [unità:][percorso] CD[..] CHKDSK Genera e visualizza una relazione sullo stato del disco e riporta gli errori individuati sul disco. Il rapporto sullo stato mostra gli errori rilevati nel sistema di archiviazione MS-DOS, consistente nella tavola allocazione file e nelle cartelle. Anche CHKDSK fornisce un riepilogo dell’uso del disco. CHKDSK non verifica che le informazioni nei file possano essere lette senza errori. MS-DOS um 106 di 138 Se vi sono errori su disco, CHKDSK visualizza un messaggio. L’utility SCANDISC è il metodo consigliato per correggere problemi su disco, da preferire al comando CHKDSK /F. CHKDSK [unità:][[percorso] nomefile] [/F] [/V] Opzioni. /F Corregge gli errori su disco, non utilizzare questa opzione se si sta eseguendo CHKDSK da altre applicazioni. /V Visualizza il nome di ciascun file contenuto in tutte le cartelle, durante il controllo del disco. Per visualizzare una relazione sullo stato del disco dell’unità corrente, utilizzare la seguente sintassi. CHKDSK COPY Copia uno o più file in un’altra posizione. Il comando COPY può essere utilizzato anche per unire file. Se sono copiati più file, MS-DOS visualizza il nome di ciascun file man mano che è copiato. COPY [Y|-Y][/A|/B] origine[/A|/B] [+ origine[/A|/B] [+ ...]][destinazione [/A|/B]] [/V] Opzioni. /A Indica un file di testo ASCII. L’opzione /A ha effetto su tutti i file che essa precede nell’elenco dei nomi di file sulla riga di comando, fino a quando COPY non incontra un’opzione /B. In tal caso, l’opzione /B ha effetto su tutti i file che la precedono. Quando l’opzione /A segue un nome di file, essa avrà effetto su quel file e su tutti i file ad essa successivi, fino a quando COPY non incontra l’opzione /B. In tal caso, l’opzione /B avrà effetto su tutti i file che la precedono. Un file di testo ASCII può utilizzare il carattere di fine file CTRL+Z, per indicare la fine di un file. Durante l’unione di file, il comando COPY considera per definizione i file come file di testo ASCII. /B Indica un file binario. L’opzione /B ha effetto su tutti i file che la precedono sulla riga di comando, fino a quando il comando COPY non incontra un’opzione /A. In tal caso, l’opzione /A avrà effetto su tutti i file che la precedono. Se l’opzione /B segue un nome di file, essa avrà effetto su quel file e su tutti i file ad essa successivi, fino a quando COPY non incontra un’opzione /A. In tal caso, l’opzione /A avrà effetto su tutti i file che la precedono. L’opzione /B specifica che l’interprete dei comandi deve leggere il numero di byte specificati dalle dimensioni dei file nella cartella. L’opzione /B è il valore predefinito di COPY, tranne quando esso sta unendo dei file. DEFRAG Riorganizza i file su un disco per ottimizzare le prestazioni del disco stesso. Non utilizzare questo comando durante l’esecuzione di Windows. DEFRAG [unità:] [/F] [/S[:]ordine] [/B] [/SKIPHIGH] [/LCD | /BW | /G0] [/H] DEFRAG [unità:] [/U] [/B] [/SKIPHIGH] [/LCD | /BW | /G0] [/H] MS-DOS um 107 di 138 Opzioni. /F Compatta i file e garantisce che nel disco non siano presenti spazi vuoti tra i file. /U Compatta i file e lascia spazi vuoti, se presenti, tra i file. /B Riavvia il PC dopo avere riorganizzato i file. /H Sposta file nascosti. DEL (Erase) Elimina i file specificati. DEL [unità:][percorso] nomefile [/P] Opzione. /P Chiede conferma prima di eliminare il file specificato. DELTREE Elimina una cartella con tutti i file e sotto cartelle relative. DELTREE [/Y] [unità:]percorso [[drive:]percorso[...]] DIR Visualizza l’elenco dei file e delle sotto cartelle di una cartella. Quando si utilizza il comando DIR senza parametri od opzioni, esso visualizza l’etichetta di volume e il numero di serie del disco. Visualizza inoltre una cartella o un file per riga, inclusa l’estensione del file, la relativa dimensione in byte, la data e l’ora dell’ultima modifica. Infine, il comando riporta il numero totale dei file elencati, la quantità totale di memoria occupata e il numero di byte lasciati liberi sul disco. DIR [unità:][percorso][nomefile] [/P] [/W] [/A[[:]attributi]][/O[[:]tipoordinamento]] [/S] [/B] [/L] [C] Opzioni. /P Visualizza l’elenco una schermata per volta. Per passare alla schermata successiva, è sufficiente premere un tasto. /W Visualizza l’elenco in formato ampio, elencando fino a cinque file o cartella per riga. /A[[:] attributi] Visualizza solo le cartelle e i file con gli attributi specificati. Se questa opzione è omessa, il comando DIR visualizza tutti i file tranne quelli nascosti e di sistema. Se l’opzione è utilizzata senza specificare gli attributi, DIR visualizza tutti i file, compresi quelli nascosti e di sistema. L’elenco che segue descrive ciascuno dei valori che è possibile utilizzare per attributi. I due punti (:) sono facoltativi. È possibile utilizzare una qualsiasi combinazione di questi valori senza separarli con spazi. H File nascosti, -H File non nascosti, S File di sistema, -S File non di sistema, D Directory -D Solo file escluse le directory, A File pronti per essere archiviati backup, -A File che non sono stati modificati dall’ultimo backup, R File di sola lettura, -R File non di sola lettura. DOSKEY Doskey è un’utility residente in memoria ed è utilizzata per personalizzare e automatizzare la riga di comando MS-DOS. Quando è installato, Doskey occupa circa 3 KB di memoria residente. DOSKEY [/REINSTALL] [/BUFSIZE=dimensione] [/MACROS] [/HISTORY][/INSERT|/OVERSTRIKE] [nomemacro=[testo]] MS-DOS um 108 di 138 EDIT Avvia MS-DOS Editor che consente di creare e modificare file di testo ASCII; è un editor a schermo intero che consente di creare, modificare, memorizzare e stampare file di testo ASCII. In MS-DOS Editor è possibile scegliere i comandi da menu e specificare le informazioni e le preferenze nelle finestre di dialogo. MS-DOS Editor comprende un’ampia Guida in linea per richiedere informazioni relative alle sue procedure e ai suoi comandi. EDIT [[unità:][percorso]nomefile ] [/B] [/G] [/H] [/NOHI] Per poter utilizzare MS-DOS Editor è necessario che il file QBASIC.EXE si trovi nella directory corrente, nel relativo percorso di ricerca o nella stessa cartella del file EDIT.COM. Se il file QBASIC.EXE è eliminato per liberare spazio sul disco, MS-DOS Editor non potrà essere eseguito. EMM386 Abilita o disabilita il supporto di memoria espansa EMM386 su un PC con CPU 80386 o superiore. Il comando EMM386 abilita o disabilita anche il supporto del coprocessore Weitek. Non utilizzare questo comando durante l’esecuzione di Windows. Esso, inoltre, provvede supporto di memoria espansa e accesso alla memoria superiore. EMM386 [ON|OFF|AUTO] Per visualizzare lo stato attuale del supporto di memoria espansa EMM386, utilizzare la sintassi seguente. EMM386 Parametri. ON|OFF|AUTO Attiva il driver di periferica EMM386.EXE se impostato su ON, sospende il driver di periferica EMM386.EXE se impostato su OFF oppure posiziona il driver di periferica EMM386.EXE in modalità automatica se impostato su AUTO. La modalità automatica abilita il supporto di memoria espansa solamente quando un programma lo richiede. Il valore predefinito ON. EXPAND Espande un file compresso. È possibile utilizzare questo comando per recuperare uno o più file dai dischi d’installazione o di aggiornamento inclusi nel pacchetto di MS-DOS. I file non possono essere utilizzati finché non sono decompressi. EXPAND [unità:][percorso]nomefile [[unità:][percorso]nomefile[...]] destinazione Se è digitato quanto segue, EXPAND chiederà d’immettere la posizione e/o il nome che si desidera assegnare al file espanso. EXPAND [unità:][percorso]nomefile EXPAND chiederà d’immettere la posizione e il nome del file compresso da espandere, quindi la posizione e/o il nome da assegnare al file espanso, se si digita quanto segue. EXPAND MS-DOS um 109 di 138 FDISK Avvia l’utility FDISK, che configura il disco rigido per l’utilizzo di MS-DOS. Visualizza una serie di menu per facilitare la suddivisione in partizioni del disco rigido per MS-DOS. FDISK Opzioni. /STATUS Visualizza una panoramica delle partizioni del disco rigido del PC, senza avviare l’utility. Per visualizzare le informazioni sulla partizione senza avviare l’utility, utilizzare la seguente sintassi. FDISK /STATUS FORMAT Formatta il disco nell’unità specificata per accettare i file di MS-DOS. Il comando FORMAT crea una nuova cartella principale e una tabella di assegnazione dei file per il disco. È anche possibile controllare le aree danneggiate sul disco ed eliminare tutti i dati sul disco. Per consentire a MS-DOS di utilizzare un disco nuovo, utilizzare questo comando per formattare il disco. FORMAT unità: [/V[:etichetta]] [/Q] [/U] [/F:dimensione][/B|/S] [/C] FORMAT unità: [/V[:etichetta]] [/Q] [/U] [/T:tracce /N:settori] [/B|/S] [/C] FORMAT unità: [/V[:etichetta]] [/Q] [/U] [/1] [/4] [/B|/S] [/C] FORMAT unità: [/Q] [/U] [/1] [/4] [/8] [/B|/S] [/C] Non formattare un disco floppy in misura maggiore a quella attribuitagli. Se il disco è stato formattato e non si sta utilizzando il parametro /U, la vecchia tabella di assegnazione dei file e la cartella principale saranno salvate per poter annullare la formattazione del disco. Se è stato formattato il disco sbagliato utilizzare il comando il più presto possibile. Opzioni. /Q Specifica una formattazione veloce di un disco. Tramite questa opzione, FORMAT elimina la FAT e la directory principale di un disco formattato in precedenza, ma non esamina il disco per verificare la presenza di aree danneggiate. Si dovrebbe utilizzare l’opzione /Q per formattare solo dischi già formattati in precedenza che non sono sicuramente danneggiati. /U Specifica un’operazione di formattazione incondizionata per un disco floppy o un disco rigido. La formattazione incondizionata distrugge tutti i dati esistenti sul disco e impedisce di annullare la formattazione in un secondo tempo. È consigliabile utilizzare /U se sono stati visualizzati messaggi di errori di lettura e di scrittura durante l’utilizzo del disco. /F:size Specifica la dimensione del disco floppy da formattare. Se possibile, utilizzare questa opzione, invece delle opzioni /T e /N. Utilizzare uno dei seguenti valori per la dimensione: 720, 1440. /B Riserva dello spazio per i file di sistema IO.SYS e MSDOS.SYS su un disco appena formattato come file nascosti. Nelle versioni precedenti di MS-DOS, era necessario riservare questo spazio prima di utilizzare il comando SYS per copiare i file di sistema sul disco. Questa opzione è mantenuta MS-DOS versione 6.0 solo per ragioni di compatibilità. MS-DOS um 110 di 138 /S Copia i file di sistema in uso IO.SYS, MSDOS.SYS e COMMAND.COM dall’unità disco di avvio del sistema su un disco formattato che può essere utilizzato come disco di sistema. Se FORMAT non riesce a trovare i file di sistema in uso, richiede l’inserimento di un disco di sistema. /C Ricontrolla i cluster danneggiati. Per impostazione predefinita, se un’unità contiene cluster segnati come “danneggiati” FORMAT non ricontrolla i cluster; li lascia semplicemente segnati come “danneggiati”. Utilizzare l’opzione /C se si desidera che FORMAT ricontrolli tutti i cluster danneggiati sull’unità. KEYB Avvia l’utility KEYB che configura una tastiera in base ad una lingua specifica. Utilizzare KEYB per configurare una tastiera per una lingua diversa dall’inglese statunitense. KEYB [xx[,[yyy][,[unità disco:][percorso]nomefile]]] [/E] [/ID:nnn] Parametri. xx Specifica il codice della tastiera. yyy Specifica la tabella codici. Se non è specificato un valore, KEYB utilizza la tabella codici corrente. [unità:][percorso]nomefile Specifica la posizione e il nome del file di definizione della tastiera. Il nome del file predefinito è KEYBOARD.SYS. Se KEYBOARD.SYS si trova in una cartella inclusa nel percorso, non sarà necessario specificare questo parametro. MS-DOS 6.22 include due file di definizione della tastiera: il file predefinito KEYBOARD.SYS e KEYBRD2.SYS, che fornisce supporto per tastiere non incluse in KEYBOARD.SYS. [unità-dos:]percorso dos Specifica la posizione del file KEYB.COM. Opzioni. /E Indica che la tastiera installata è avanzata, tale opzione risulta utile se si utilizza una tastiera avanzata su un PC 8086. /ID:nnn Specifica il tipo di tastiera in uso. Questa opzione è necessaria solo per i paesi che hanno più schemi di tastiera per la stessa lingua Francia, Italia e Regno Unito. Per esempio, la Tabella Identificazione codici della tastiera Paese o lingua (valore xx) (valore yyy) (valore ID:nnn) Italia it 850 437 Stati Uniti us 850 437. LABEL Crea, modifica o elimina l’etichetta di volume, nome, di un disco. MS-DOS visualizza l’etichetta di volume all’interno dell’elenco della cartella. MS-DOS visualizza anche il numero di serie del volume, se è disponibile. LABEL [unità:][etichetta] Per indicare a MS-DOS di visualizzare l’etichetta di volume e il numero di serie correnti, se esistono e di richiedere l’immissione di un’etichetta o l’eliminazione di quella esistente, utilizzare la seguente sintassi. LABEL MEM Visualizza la quantità di memoria utilizzata e la quantità di memoria libera nel sistema. MS-DOS um 111 di 138 È possibile utilizzare il comando MEM per visualizzare le informazioni relative alle aree di memoria utilizzate, alle aree di memoria libere e alle applicazioni caricate in memoria. MEM [/CLASSIFY|/DEBUG|/FREE|/MODULE nomemodulo] [/PAGE] Opzioni. /CLASSIFY Elenca le applicazioni che sono state caricate effettivamente nella memoria e visualizza la quantità di memoria convenzionale e di memoria superiore utilizzata da ogni applicazione. MEM /CLASSIFY Fornisce anche un sommario dell’utilizzo di memoria ed elenca i blocchi di memoria più grandi a disposizione. È possibile utilizzare l’opzione seguente. /CLASSIFY con /PAGE, ma non con altre opzioni di MEM. L’opzione /CLASSIFY può essere abbreviata in /C. /FREE Elenca le aree di memoria convenzionale e superiore libere. MEM/FREE Visualizza l’indirizzo del segmento, la dimensione di ogni area di memoria convenzionale libera e il blocco più grande libero in ogni area di memoria superiore. È possibile utilizzare l’opzione /FREE con /PAGE, ma non con altre opzioni di MEM. Si può abbreviare /FREE in /F. /PAGE Fa una pausa dopo ogni schermata di output. Questa opzione può essere utilizzata con altre opzioni di MEM. Per visualizzare lo stato della memoria utilizzata e della memoria libera del sistema, utilizzare la seguente sintassi. MEM MKDIR (MD) Crea una cartella. È possibile utilizzare il comando MKDIR per creare una struttura di directory su più livelli. MKDIR [unità:]percorso MD [unità:]percorso MSCDEX Fornisce accesso alle unità CD-ROM. MSCDEX può essere caricato dal file AUTOEXEC.BAT o dal prompt dei comandi. Il driver di periferica che fa parte dell’unità CD-ROM deve essere caricato dal file CONFIG.SYS. Il comando MSCDEX non dovrebbe essere utilizzato dopo che Windows è stato avviato. MSCDEX /D:periferica [/D:periferica2... ] [/E] [/K] [/S] [/V] [/L:lettera] [/M:numero] Parametri. /D:periferica1 [/D:periferica2... ] Specifica la signature del driver del primo driver di periferica CD-ROM. Il parametro periferica1 deve coincidere con il parametro specificato dall’opzione /D sul comando CONFIG.SYS che avvia il driver di periferica corrispondente CD-ROM. Il comando MSCDEX deve includere almeno un’opzione /D. Per installare dei driver di periferica CD-ROM addizionali, specificare un’opzione addizionale /D per ciascun driver. /E Specifica che il driver CD-ROM deve essere predisposto in modo da espandere memoria, se ne esiste disponibile, per archiviare dei buffer di settore. /V Indica a MSCDEX di visualizzare delle statistiche di visualizzazione della memoria quando è avviato. /L:lettera Specifica le lettere dell’unità da assegnare alla prima unità CD-ROM. MS-DOS um 112 di 138 Se si ha più di un’unità CD-ROM, MS-DOS assegna delle unità addizionali conseguenti alle lettere dell’unità disponibili. /M:numero Specifica il numero di buffer di settore. PATH Imposta un percorso di ricerca per file eseguibili. MS-DOS utilizza il comando PATH per cercare i file eseguibili nelle cartelle specificate. Il percorso di ricerca predefinito è solo la cartella corrente. PATH [[unità:]percorso[;...]] Per visualizzare il percorso di ricerca corrente, utilizzare la sintassi seguente. PATH Per eliminare tutte le impostazioni dei percorsi di ricerca e lasciare soltanto quella predefinita, la directory corrente, utilizzare la seguente sintassi. PATH; Quando è specificato da solo, elimina tutte le impostazioni dei percorsi e indica a MS-DOS di ricercare soltanto nella cartella corrente. PRINT Stampa un file di testo durante l’elaborazione di altri comandi MS-DOS. Se si dispone di una periferica di output, collegata ad una delle porte seriali o parallele del sistema, con il comando PRINT sarà possibile stampare in background. PRINT [/D:periferica] [/B:dimensioni] [/U:tic1] [/M:tic2] [/S:tic3] [/Q:dimensionicoda] [/T] [[unità:][percorso] nomefile[ ...]] [/C] [/P] P Opzioni. /D:periferica Specifica il nome della periferica di stampa. I valori validi delle porte parallele sono LPT1, LPT2 e LPT3. I valori validi delle porte seriali sono COM1, COM2, COM3 e COM4. Il valore predefinito è PRN. I valori PRN e LPT1 si riferiscono alla stessa porta parallela. L’opzione /D deve precedere il nome di qualsiasi file sulla riga di comando. /T Elimina tutti i file dalla coda di stampa. Per installare il comando PRINT utilizzando i parametri predefiniti o per visualizzare il contenuto della coda di stampa senza modificarla, la sintassi sarà la seguente. PRINT PROMPT Modifica l’aspetto del prompt dei comandi di MS-DOS. È possibile personalizzare l’aspetto del prompt dei comandi in maniera tale da visualizzare una qualsiasi stringa di testo, con informazioni quali il nome della directory corrente, l’ora e la data e il numero della versione di MS-DOS. PROMPT [testo] Testo. $Q = (segno di uguale). $$ $ (simbolo del dollaro). $T Ora corrente. $D Data corrente. $P Unità e percorso corrente. $V Numero della versione di MS-DOS. MS-DOS um 113 di 138 $N Unità corrente. $G > (segno di maggiore). $L < (segno di minore). $B | (pipe). $_ INVIO-NUOVA RIGA. $E Il codice escape ASCII (codice 27). $H BACKSPACE (elimina un carattere che è stato scritto sulla riga di prompt). RENAME (REN) Cambia il nome di uno o più file. È possibile assegnare un nuovo nome a tutti i file che corrispondono al nome specificato. Non è possibile utilizzare questo comando per assegnare un nuovo nome a file di unità diverse o per spostarli in nuove cartelle. Per rinominare le sotto cartella o spostare i file, utilizzare il comando. RENAME [unità:][percorso]nomefile1 nomefile2 REN [unità:][percorso]nomefile1 nomefile2 RMDIR (RD) Elimina (rimuove) una cartella. Prima di eliminare una cartella, è necessario eliminare prima tutti i file e le sotto cartelle contenuti in essa. La cartella deve essere vuota, fatta eccezione per i simboli (.) e (..). RMDIR [unità:]percorso RD [unità:]percorso SCANDISK Avvia Microsoft SCANDISK, un’utilità di scansione e ripristino che controlla una data unità per rilevare degli errori e correggere eventuali problemi. SCANDISK [unità: [unità: ...]|/ALL] [/CHECKONLY | /AUTOFIX [/NOSAVE] | CUSTOM] [/SURFACE] [/MONO] [/NOSUMMARY] Opzioni. /ALL Controlla e ripristina tutte le unità locali. /AUTOFIX Corregge gli errori senza chiedere prima conferma. Per impostazione predefinita, avviando SCANDISK con l’opzione /AUTOFIX tutti i cluster persi rilevati sull’unità, saranno salvati come file nella cartella principale dell’unità. Per fare in modo che SCANDISK elimini i cluster persi invece di salvarli, includere l’opzione /NOSAVE. Utilizzando l’opzione /AUTOFIX, se sono rilevati errori sarà richiesto un disco Undo. Per evitarlo, includere l’opzione /NOSUMMARY. Non è possibile utilizzare l’opzione /AUTOFIX unitamente alle opzioni /CHECKONLY o /CUSTOM. /CHECKONLY Controlla una data unità per rilevarvi degli errori, ma non li corregge. Non si può usare questa opzione unitamente alle opzioni /AUTOFIX or /CUSTOM. /NOSAVE Fa in modo che SCANDISK elimini tutti i cluster persi rilevati. Può essere utilizzato solo unitamente all’opzione /AUTOFIX. Se si avvia SCANDISK con l’opzione /AUTOFIX omettendo l’opzione /NOSAVE, ScanDisk salverà il contenuto dei cluster persi come file nella cartella principale dell’unità. /SURFACE Esegue automaticamente una scansione della superficie dell’unità dopo aver controllato altre aree. Con una scansione della superficie di un’unità non compressa, SCANDISK conferma che i MS-DOS um 114 di 138 dati possono essere scritti e letti con sicurezza. Con la scansione di un’unità compressa SCANDISK conferma che i dati possono essere decompressi. È consigliabile esaminare periodicamente la superficie di tutte le unità. In base all’impostazione predefinita, una volta terminato l’esame del file system di una data unità, SCANDISK chiede se si desidera effettuare una scansione della superficie. Con l’opzione /SURFACE tale scansione è effettuata senza chiedere conferma. Se si usa /SURFACE unitamente all’opzione /CUSTOM esso ha la precedenza sulle impostazioni di superficie nella sezione [Custom] del file SCANDISK.INI. SMARTDRV Avvia o configura l’utility SMARTDRIVE la quale crea una cache del disco nella memoria estesa. Una cache del disco può velocizzare in modo significativo le operazioni di MS-DOS. Quando è utilizzato per l’operazione di caching del disco, SMARTDRIVE è caricato utilizzando il comando SMARTDRV nel file AUTOEXEC.BAT o al prompt dei comandi. SMARTDRIVE può anche eseguire un doppio buffering, il quale è compatibile per i controller del disco rigido che non possono funzionare con la memoria fornita da EMM386 o Windows eseguito in modalità 386 avanzata. Per utilizzare il doppio buffering, caricare il driver di periferica utilizzando un comando DEVICE nel file CONFIG.SYS. Il comando SMARTDRV non sarà caricato dopo che Windows è stato avviato. Sintassi. Quando si avvia SMARTDRIVE dal file AUTOEXEC.BAT o dal prompt dei comandi, utilizzare la seguente sintassi. [unità:][percorso]SMARTDRV [/X] [[unità[+|-]]...] [/U] [/C|/R] [/F|/N] [/L] [/V|/Q|/S] [DimCacheIniz][DimCacheWin]] [/E:DimElemen] [/B: ] Quando inizia l’esecuzione di SMARTDRIVE, utilizzare la seguente sintassi. SMARTDRV [/X] [[unità[+|-]]...]] [/C|/R] [/F|/N] [/Q|/S] Per visualizzare lo stato corrente dopo che è stato caricato SMARTDRIVE, usare la sintassi seguente. SMARTDRV Se si specifica una lettera dell’unità senza un segno di addizione o sottrazione, l’opzione di caching di lettura è attivata e quella di scrittura è disattivata. Se si specifica una lettera dell’unità seguita da un segno di addizione, le due opzioni sono attivate. Se si specifica una lettera dell’unità seguita da un segno di sottrazione, le opzioni sono disattivate. Se non si specifica una lettera dell’unità, le unità dischi floppy, CD-ROM e le unità create utilizzando INTERLNK sono attivate con l’opzione di lettura ma non di scrittura, i dischi fissi con entrambe le opzioni attivate e le unità di rete e le schede di memoria flash sono ignorate. Dimcacheiniz Specifica la dimensione in KB della cache quando SMARTDRIVE è avviato, quando Windows non è eseguito. DimCacheWin Specifica, in KB, in che misura SMARTDrive ridurrà la dimensione della cache per Windows. Quando è avviato Windows, SMARTDRIVE riduce la dimensione della cache per recuperare memoria per l’utilizzo di Windows. Opzioni. /X Disattiva il caching write-behind per tutte le unità. MS-DOS um 115 di 138 È possibile quindi attivare il caching per le singole unità usando il parametro unità+|-. /U Non carica il modulo caching CD-ROM di SMARTDRIVE anche se si possiede un’unità CD-ROM. Se è caricato SMARTDRIVE con l’opzione /U, non è possibile attivare il caching dell’unità CD-ROM. Se è caricato SMARTDRIVE senza l’opzione /U, è possibile disattivare o attivare il caching di singole unità CD-ROM usando il parametro dell’unità+|-. /C Scrive tutte le informazioni di cui è stato eseguito il caching dalla memoria sui dischi. SMARTDRIVE scrive informazioni dalla memoria sul disco a volte quando altra attività del disco è rallentata. Si potrebbe utilizzare questa opzione se si sta spegnendo il PC e si vuole assicurare che le informazioni cache sono state scritte sul disco. SMARTDRIVE scrive tutte le informazioni cache sul disco se si riavvia il PC premendo CTRL+ALT+CANC, ma non se si spegne o si preme il pulsante di riavvio. /S Visualizza informazioni addizionali circa lo stato di SMARTDRIVE. Controllare che SMARTDRIVE abbia completato l’opzione di cache di scrittura prima di riavviare o spegnere il PC. Questo non è necessario se si riavvia il PC premendo CTRL+ALT+CANC. Per fare in modo che SMARTDRIVE scriva tutte le informazioni di cui è stato eseguito il caching sui dischi, digitare SMARTDRV /C al prompt dei comandi. Dopo che l’attività del disco è stata interrotta, è possibile riavviare il PC per sicurezza o spegnere il PC. SUBST Associa un percorso ad una lettera di unità. La lettera di unità assegnata rappresenta un’unità virtuale dato il suo possibile uso come unità fisica all’interno dei comandi. Non usare il comando SUBST quando Windows è in esecuzione. SUBST [unità1: [unità2:]percorso] SUBST unità1: /D Opzione. /D Elimina un’unità virtuale. Per visualizzare i nomi delle unità virtuali attive, utilizzare la seguente sintassi. SUBST SYS Crea un disco di avvio, copiando sul disco i file di sistema di MS-DOS, IO.SYS e MSDOS.SYS, l’interprete dei comandi MS-DOS COMMAND.COM e la parte di MS-DOS che fornisce accesso alle unità compresse DRVSPACE.BIN. Il comando SYS copierà il file DRVSPACE.BIN solo se tale file si trova nella cartella principale dell’unità o della directory di origine, IO.SYS, MSDOS.SYS e DRVSPACE.BIN sono file nascosti e pertanto non compaiono negli elenchi delle cartelle visualizzate dal comando DIR. Per visualizzare questi file, digitare DIR /A. SYS [unità1:][percorso] unità2: TYPE Visualizza il contenuto di un file di testo. Utilizzare il comando TYPE per visualizzare un file di testo senza modificarlo. TYPE [unità:][percorso]nomefile MS-DOS um 116 di 138 UNDELETE Ripristina i file eliminati in precedenza con il comando, UNDELETE fornisce tre livelli di protezione dei file da eliminazioni accidentali: metodo Sentry di eliminazione, metodo Registro di eliminazione e metodo Standard. UNDELETE [[unità:][percorso]nomefile] [/DT|/DS|/DOS] UNDELETE [/LIST|/ALL|/PURGE[unità]|/STATUS|/LOAD|/UNLOAD|/S[unità ]|/Tunità [voci]] Opzioni. /LIST Elenca i file eliminati che sono disponibili per il recupero, ma non recupera alcun file. Il parametro [unità:][percorso]nomefile e le opzioni /DT, /DS e /DOS controllano l’elenco fornito dall’opzione. /DOS Recupera soltanto i file elencati come file eliminati da MS-DOS, chiedendo conferma per ciascuno di essi. Se esiste un file di registrazione dell’eliminazione, l’opzione indica a UNDELETE di ignorarlo. /LOAD Carica nella memoria UNDELETE, un’applicazione residente in memoria, utilizzando le informazioni definite nel file UNDELETE.INI. Se il file UNDELETE.INI non esiste, UNDELETE utilizzerà i valori predefiniti. /UNLOAD Rimuove la porzione di UNDELETE che risiede in memoria, impedendo in tal modo il ripristino dei file eliminati. UNFORMAT Ripristina un disco cancellato dal comando FORMAT. UNFORMAT ripristina solo unità disco rigido o floppy locali, mentre non può essere utilizzato per ripristinare unità di rete. Il comando UNFORMAT può inoltre ricostruire una tabella delle partizioni del disco danneggiate su un’unità disco rigido. UNFORMAT unità: [/L] [/TEST] [/P] Opzioni. /L Elenca tutti i file e le sotto cartelle trovate da UNFORMAT. Se questa opzione non è specificata, UNFORMAT elenca solo le sotto cartelle e i file frammentati. Per sospendere lo scorrimento dell’elenco visualizzato, premere la combinazione di tasti CTRL+S. Per riprendere lo scorrimento, premere un tasto qualsiasi. VER Visualizza il numero della versione di MS-DOS. VER VOL Visualizza l’etichetta di volume e il numero di serie del disco, se esistenti. VOL [unità:] XCOPY Copia file ad eccezione dei file di sistema, nascosti e cartelle, incluse le sotto cartelle. Con questo comando è possibile copiare tutti i file di una cartella, compresi i file nelle MS-DOS um 117 di 138 relative sotto cartelle. XCOPY origine [destinazione] /Y|/-Y] [/A|/M] [/D:data] [/P] [/S] [/E] [/V] [/W] Opzioni. /Y Indica che XCOPY sostituisce i file esistenti senza chiedere conferma. Per impostazione predefinita, se si specifica un file come file di destinazione, XCOPY chiederà se si desidera sovrascrivere il file esistente. Le versioni precedenti di MS-DOS sostituiscono semplicemente il file esistente. Se il comando XCOPY è parte di un file batch, XCOPY si comporterà come nelle precedenti versioni. Specificando questa opzione si ha la precedenza su tutte le impostazioni predefinite e correnti della variabile d’ambiente COPYCMD. /-Y Indica che XCOPY chiede la conferma quando sostituisce un file esistente. Specificando questa opzione si ha la precedenza su tutte le impostazioni predefinite e correnti della variabile d’ambiente COPYCMD. /P Chiede conferma alla creazione di ciascun file di destinazione con un messaggio. /S Copia le cartelle e le sotto cartelle, purché non siano vuote. Se è omessa questa opzione, XCOPY ha effetto solo all’interno di una singola cartella. /E Copia qualsiasi sotto cartella, anche se vuota. Con questa opzione è necessario utilizzare l’opzione /S. ANSI.SYS Definisce le funzioni che modificano gli elementi grafici dello schermo, controllano i movimenti del cursore e riassegnano i tasti. Il driver della periferica ANSI.SYS supporta l’emulazione terminale ANSI della sequenza di escape per controllare lo schermo e la tastiera del sistema. Una sequenza di escape ANSI è una sequenza di caratteri ASCII, i primi due dei quali sono il carattere escape (1BH) e il carattere parentesi sinistra (5BH). I caratteri che seguono questi due specificano un codice alfanumerico che controlla una funzione della tastiera o dello schermo. Le sequenze di escape ANSI rilevano la differenza tra lettere maiuscole e minuscole. Le lettere “A” e “a”, ad esempio, hanno due significati completamente diversi. Questo driver della periferica deve essere caricato da un comando. DEVICE o DEVICEHIGH nel file CONFIG.SYS. DEVICE=[unità:][percorso]ANSI.SYS [/X] [/K] [/R] Opzioni. [unità:][percorso] Specifica la posizione del file ANSI.SYS. /X Riassegna i tasti estesi indipendentemente sulle tastiere a 101 tasti. /K Fa sì che ANSI.SYS gestisca una tastiera a 101 tasti come una da 84 tasti. È l’equivalente del comando SWITCHES=/K. Se in genere si utilizza il comando SWITCHES=/K, sarà necessario utilizzare l’opzione /K con il file ANSI.SYS. /R Regola lo scorrimento delle righe per migliorare la leggibilità quando ANSI.SYS è utilizzato con le applicazioni che facilitano l’utilizzo dei PC agli utenti con particolari esigenze. Parametri utilizzati nelle sequenze di escape ANSI. Pn Parametro numerico, specifica un numero decimale. Ps Parametro di selezione, specifica un numero decimale che è utilizzato per selezionare una funzione. È possibile specificare più funzioni separando i parametri con (;). Pl Parametro di riga, specifica un numero decimale che rappresenta una delle righe sullo MS-DOS um 118 di 138 schermo o su un’altra periferica. Pc Parametro di colonna, specifica un numero decimale che rappresenta una delle colonne sullo schermo o su un’altra periferica. Sequenze di escape ANSI per i movimenti del cursore, la grafica e le impostazioni della tastiera: nel seguente elenco di sequenze di escape ANSI, l’abbreviazione ESC rappresenta il carattere di escape ASCII 27 (1BH), che appare all’inizio di ciascuna sequenza di escape. ESC[PL;PcH Posizione del cursore: sposta il cursore in corrispondenza delle coordinate specificate. Se non è specificata alcuna posizione, il cursore sarà spostato nell’angolo superiore sinistro dello schermo (riga 0, colonna 0), vale a dire nella stessa posizione di quando si preme il tasto HOME. Questa sequenza di escape funziona nello stesso modo della sequenza che segue. ESC[PL;Pcf Posizione del cursore: questa sequenza di escape funziona nello stesso modo della sequenza precedente. ESC[PnA Cursore verso l’alto: sposta il cursore verso l’alto per il numero di righe specificato senza cambiare colonna. Se il cursore è già posto sulla prima riga, ANSI.SYS ignorerà la sequenza. ESC[PnB Cursore verso il basso: sposta il cursore verso il basso per il numero di righe specificato senza cambiare colonna. Se il cursore è già posto sull’ultima riga, ANSI.SYS ignorerà la sequenza. ESC[PnC Cursore in avanti: sposta il cursore verso la fine della riga per il numero di colonne specificato senza cambiare riga. Se il cursore è già posto nella colonna più a destra, ANSI.SYS ignorerà la sequenza. ESC[PnD Cursore all’indietro: sposta il cursore verso l’inizio della riga per il numero di colonne specificato senza cambiare riga. Se il cursore è già posto nella colonna più a sinistra, ANSI.SYS ignorerà la sequenza. ESC[s Salvataggio della posizione del cursore: salva la posizione corrente del cursore. È possibile spostare il cursore alla posizione salvata utilizzando la sequenza per il ripristino della posizione del cursore. ESC[u Ripristino della posizione del cursore: sposta il cursore alla posizione memorizzata dalla sequenza per il salvataggio della posizione del cursore. ESC[2J Cancellazione di schermo: cancella il contenuto dello schermo e sposta il cursore nell’angolo superiore sinistro (riga 0, colonna 0). ESC[K Cancellazione di riga: cancella tutti i caratteri dalla posizione del cursore fino alla fine della riga incluso il carattere in corrispondenza del cursore. ESC[Ps;...;Psm Impostazione della modalità grafica: chiama le funzioni grafiche specificate dai seguenti valori. Queste funzioni specifiche rimangono attive fino alla successiva occorrenza di questa sequenza di escape. La modalità grafica modifica i colori e gli attributi di testo quali il grassetto e la sottolineatura visualizzati. Attributi di testo. 0 Tutti gli attributi disattivati. 1 Grassetto attivato. 4 Sottolineato (solo su schede video monocromatiche). 5 Lampeggiamento attivato. 7 Video inverso attivato. 8 Nascosto attivato. Colori di primo piano. 30 Nero. 31 Rosso. 32 Verde. 33 Giallo. MS-DOS um 119 di 138 34 Blu. 35 Fucsia. 36 Azzurro. 37 Bianco. Colori di sfondo. 40 Nero. 41 Rosso. 42 Verde. 43 Giallo. 44 Blu. 45 Fucsia. 46 Azzurro 47 Bianco. I parametri compresi tra 30 e 47 sono conformi allo standard ISO (International Standard Organization) 6429. ESC[=psh Impostazione di modalità: modifica la larghezza dello schermo o il tipo di modalità specificato da uno dei seguenti valori. 0 40 X 148 X 25 monocromatico (testo). 1 40 X 148 X 25 a colori (testo). 2 80 X 148 X 25 monocromatico (testo). 3 80 X 148 X 25 a colori (testo). 4 320 X 148 X 200 a 4 colori (grafica). 5 320 X 148 X 200 monocromatico (grafica). 6 640 X 148 X 200 monocromatico (grafica). 7 Attiva il ritorno a capo automatico delle righe. 13 320 X 148 X 200 a colori (grafica). 14 640 X 148 X 200 a colori (grafica a 16 colori). 15 640 X 148 X 350 monocromatico (grafica a 2 colori). 16 640 X 148 X 350 a colori (grafica a 16 colori). 17 640 X 148 X 480 monocromatico (grafica a 2 colori). 18 640 X 148 X 480 a colori (grafica a 16 colori). 19 320 X 148 X 200 a colori (grafica a 256 colori). ESC[=Psl Ripristino di modalità: ripristina la modalità utilizzando gli stessi valori utilizzati dall’Impostazione di modalità, eccetto il valore 7, che consente il ritorno a capo automatico delle righe. L’ultimo carattere in questa sequenza di escape è una lettera L minuscola. ESC[codice;stringa;...p Impostazione delle stringhe da tastiera: imposta di nuovo un tasto ad una stringa specificata. I parametri sono definiti nel seguente modo. o “Codice” corrisponde a uno o più valori elencati nella tabella che segue. Questi valori rappresentano tasti e combinazioni di tasti. Quando si utilizzano questi valori nel comando, è necessario digitare il punto e virgola (;) indicato nella tabella oltre a quelli richiesti dalla sequenza di escape. I codici racchiusi fra parentesi non sono disponibili su alcune tastiere. ANSI.SYS non interpreterà tali codici per queste tastiere a meno che non sia specificata l’opzione /X nel comando DEVICE in ANSI.SYS. o “Stringa” è il codice ASCII per un singolo carattere o una stringa racchiusa tra virgolette (“ ”). Ad esempio, sia 65 sia “A” possono essere utilizzate per rappresentare una A maiuscola. Alcuni valori nella seguente tabella non sono validi per tutti i PC. Verificare nella documentazione del PC i valori che sono diversi. Tasto Codice MAIUSC+codice CTRL+codice ALT+codice. F1 0;59 0;84 0;94 0;104 F2 0;60 0;85 0;95 0;105 MS-DOS um 120 di 138 F3 0;61 0;86 0;96 0;106 F4 0;62 0;87 0;97 0;107 F5 0;63 0;88 0;98 0;108 F6 0;64 0;89 0;99 0;109 F7 0;65 0;90 0;100 0;110 F8 0;66 0;91 0;101 0;111 F9 0;67 0;92 0;102 0;112 F10 0;68 0;93 0;103 0;113 F11 0;133 0;135 0;137 0;139 F12 0;134 0;136 0;138 0;140 HOME (Tn) 0;71 55 0;119 -Freccia SU (Tn) 0;72 56 (0;141) -PGSU (Tn) 0;73 57 0;132 -Freccia SINISTRA (Tn) 0;75 52 0;115 -Freccia DESTRA (Tn) 0;77 54 0;116 -FINE (Tn) 0;79 49 0;117 -Freccia GIÙ (Tn) 0;80 50 (0;145) -PGGIÙ (Tn) 0;81 51 0;118 -INS (Tn) 0;82 48 (0;146) -CANC (Tn) 0;83 46 (0;147) -HOME (224;71) (224;71) (224;119) (224;151) Freccia SU (224;72) (224;72) (224;141) (224;152) PGSU (224;73) (224;73) (224;132) (224;153) Freccia SINISTRA (224;75) (224;75) (224;115) (224;155) Freccia DESTRA (224;77) (224;77) (224;116) (224;157) FINE (224;79) (224;79) (224;117) (224;159) Freccia GIÙ (224;80) (224;80) (224;145) (224;154) PGGIÙ (224;81) (224;81) (224;118) (224;161) INS (224;82) (224;82) (224;146) (224;162) CANC (224;83) (224;83) (224;147) (224;163) STAMP -- -- 0;114 -PAUSA/INTERR -- -- 0;0 - BACKSPACE 8 8 127 (0) INVIO 13 -- 10 (0 TAB 9 0;15 (0;148) (0;165) NULL 0;3 - - - - -A 97 65 1 0;30 B 98 66 2 0;48 C 99 66 3 0;46 D 100 68 4 0;32 E 101 69 5 0;18 F 102 70 6 0;33 G 103 71 7 0;34 H 104 72 8 0;35 I 105 73 9 0;23 J 106 74 10 0;36 K 107 75 11 0;37 L 108 76 12 0;38 M 109 77 13 0;50 N 110 78 14 0;49 O 111 79 15 0;24 P 112 80 16 0;25 Q 113 81 17 0;16 R 114 82 18 0;19 MS-DOS um 121 di 138 S 115 83 19 0;31 T 116 84 20 0;20 U 117 85 21 0;22 V 118 86 22 0;47 W 119 87 23 0;17 X 120 88 24 0;45 Y 121 89 25 0;21 Z 122 90 26 0;44 1 49 33 -- 0;120 2 50 64 0 0;121 3 51 35 -- 0;122 4 52 36 -- 0;123 5 53 37 -- 0;124 6 54 94 30 0;125 7 55 38 -- 0;126 8 56 42 -- 0;126 9 57 40 -- 0;127 0 48 41 -- 0;129 - 45 5 31 0;130 = 61 43 --- 0;131 [ 91 123 27 0;26 ] 93 125 29 0;27 92 124 28 0;43 ; 59 58 -- 0;39 ‘ 39 34 -- 0;40 , 44 60 -- 0;51 . 46 62 -- 0;52 / 47 63 -- 0;53 ` 96 126 -- (0;41) INVIO (Tn) 13 -- 10 (0;166) / (Tn) 47 47 (0;142) (0;74) * (Tn) 42 (0;144) (0;78) -- (Tn) 45 45 (0;149) (0;164) + (Tn) 43 43 (0;150) (0;55) 5 (Tn) (0;76) 53 (0;143) – DBLBUFF.SYS Carica il driver della periferica DBLBUFF.SYS per eseguire la doppia bufferizzazione. La doppia bufferizzazione crea compatibilità per certi controller di disco rigido che non possono funzionare con la memoria fornita da EMM386 o Windows eseguito in modalità 386 avanzata. Se durante l’installazione di Windows è determinato che il sistema necessita della doppia bufferizzazione, sarà aggiunta la voce DoubleBuffer = 1 alla sezione [Options] di MSDOS.SYS, che consentirà il caricamento automatico di DBLBUFF.SYS. Per attivare manualmente la doppia bufferizzazione, è possibile aggiungere la voce appena indicata nel file MSDOS.SYS oppure aggiungere un comando DEVICE nel file CONFIG.SYS. DEVICE=[unità:][percorso]DBLBUFF.SYS [/D+] Opzioni. [unità:][percorso] Specifica la posizione del file DBLBUFF.SYS. /D+ Indica che DBLBUFF.SYS deve sempre eseguire la doppia bufferizzazione di tutto l’I/O su disco. MS-DOS um 122 di 138 In base all’impostazione predefinita, la doppia bufferizzazione sarà eseguita solo per l’I/O verso i blocchi di memoria superiore e sarà interrotta automaticamente se non risulterà necessaria. DISPLAY.SYS Consente di visualizzare i set di caratteri internazionali sui monitor EGA (Enhanced Graphics Adapter), VGA e LCD (Liquid Crystal Display). Questo driver della periferica deve essere caricato da un comando DEVICE o DEVICEHIGH nel file CONFIG.SYS. DEVICE=[unità:][percorso]DISPLAY.SYS CON[:]=(tipo[,[tchw][,n]]) DEVICE=[unità:][percorso]DISPLAY.SYS CON[:]=(tipo[,[tchw][,(n,m)]]) Opzioni. [unità:][percorso] Specifica la posizione del file DISPLAY.SYS. tipo Specifica la scheda video in uso. I valori validi includono EGA e LCD. Il valore EGA supporta sia le schede EGA sia VGA. Se è omesso il parametro “tipo”, DISPLAY.SYS eseguirà una verifica dell’H/W per determinare il tipo di scheda video in uso. Per “tipo” è inoltre possibile specificare i valori CGA (Color Graphics Adapter) e MONO, ma non avranno alcun effetto in quanto la caratteristica di cambiamento del set di caratteri non è attivata per queste periferiche. tchw Specifica il numero del set di caratteri supportato dall’H/W in uso. Nel seguente elenco sono indicati i set di caratteri che sono supportati da MS-DOS e il paese e la lingua per ciascun set. 437 Statunitense. 850 Multilingue (Latina I). 852 Slava (Latina II). 860 Portoghese. 863 Franco-Canadese. 865 Nordica. I set di caratteri aggiuntivi sono supportati dai file EGA2.CPI e EGA3.CPI. n Specifica il numero di set di caratteri che può essere supportato dall’H/W in aggiunta al set principale specificato nel parametro tchw. I valori validi per n sono compresi tra 0 e 6. Questo valore dipende dall’H/W. Per le schede video EGA, il valore massimo per n è 6 per le schede video LCD, il valore massimo per n è 1. m Specifica il numero di caratteri secondari che può essere supportato dall’H/W per ciascuna tabella codici. Il valore predefinito è 2 se tipo è impostato a EGA, 1 se tipo è impostato a LCD. DRVSPACE.SYS, DBLSPACE.SYS Determina la posizione definitiva in memoria di DRVSPACE.BIN o DBLSPACE.BIN, la parte di MS-DOS che fornisce l’accesso alle unità compresse. DxxSPACE.SYS carica il driver in modalità reale nei blocchi di memoria superiore. In questo modo è possibile risparmiare 60 K di memoria convenzionale quando si esegue Windows 95 in modalità reale e almeno 100 K se si utilizza Microsoft Plus! Per Windows. Quando si avvia il sistema, DRVSPACE.BIN o DBLSPACE.BIN è caricato insieme alle altre funzioni del SO, prima che siano eseguiti i comandi nei file CONFIG.SYS e AUTOEXEC.BAT. Il file DXXSPACE.BIN è inizialmente caricato nella memoria convenzionale prima dei driver della periferica che forniscono l’accesso alla memoria superiore. MS-DOS um 123 di 138 Quando si utilizza DRIVESPACE o DOUBLESPACE per creare un’unità compressa sul PC, è aggiunto un comando per DxxSPACE.SYS al file CONFIG.SYS. Nella sintassi che segue, al posto di DxxSPACE digitare il nome di file per l’applicazione che si sta utilizzando. DEVICE=[unità:][percorso]DxxSPACE.SYS /MOVE [/NOHMA] [/LOW] DEVICEHIGH=[unità:][percorso]DxxSPACE.SYS /MOVE [/NOHMA] [/LOW] Opzioni. /MOVE Sposta DXXSPACE.BIN nella posizione definitiva in memoria. Inizialmente DXXSPACE.BIN è caricato nella parte alta della memoria convenzionale. Dopo che Windows ha terminato di eseguire i comandi nel file CONFIG.SYS, DXXSPACE.BIN è spostato nella parte bassa della memoria convenzionale. Quando DXXSPACE.SYS è caricato utilizzando il comando DEVICE, sposta DXXSPACE.BIN dalla parte alta della memoria convenzionale a quella bassa. In questo modo, possono essere evitati i conflitti con le applicazioni che sono caricate dal file CONFIG.SYS e che richiedono l’accesso alla parte alta della memoria convenzionale. Quando DXXSPACE.SYS è caricato utilizzando il comando DEVICEHIGH, DXXSPACE.BIN è spostato nella memoria superiore, se disponibile. Lo spostamento di DXXSPACE.BIN nella memoria superiore rende disponibile ulteriore memoria convenzionale. /NOHMA Fa in modo che DXXSPACE.SYS non sposti parte di DXXSPACE.BIN nell’area di memoria alta HMA. Se MS-DOS è caricato nell’HMA, DXXSPACE.SYS sposterà parte di DXXSPACE.BIN nell’HMA se lo spazio disponibile è sufficiente. Utilizzare quest’opzione se non si desidera che DXXSPACE.BIN utilizzi aree di memoria alta. /LOW Fa in modo che DXXSPACE.SYS non sia caricato nella parte alta della memoria convenzionale. Utilizzare quest’opzione se si dispone di un’applicazione per MS-DOS che non supporta DRIVESPACE o DOUBLESPACE nella parte alta della memoria convenzionale. L’utilizzo di quest’opzione farà sì che Windows non riutilizzi la memoria occupata da DXXSPACE.SYS. [unità:][percorso] Specifica la posizione del file Dxxspace.sys. EGA.SYS Salva e ripristina la visualizzazione quando il Task Swapper della Shell di MS-DOS è utilizzato con i monitor EGA. Se si dispone di un monitor EGA, sarà necessario installare il driver della periferica EGA.SYS prima di utilizzare il Task Swapper. Questo driver deve essere caricato da un comando DEVICE o DEVICEHIGH nel file CONFIG.SYS. DEVICE=[unità:][percorso]EGA.SYS Opzioni. [unità:][percorso] Specifica la posizione del file Ega.sys. EMM386.EXE Fornisce l’accesso all’area di memoria alta e utilizza la memoria estesa per simulare la memoria espansa. Questo driver della periferica deve essere caricato da un comando DEVICE nel file CONFIG.SYS e può essere utilizzato solo su PC con CPU 80386 o superiore. EMM386 utilizza la memoria estesa per simulare la memoria espansa per le applicazioni MS-DOS um 124 di 138 che utilizzano quest’ultimo tipo di memoria. EMM386 rende inoltre possibile caricare le applicazioni e i driver della periferica nei blocchi di memoria superiore UMB. DEVICE=[unità:][percorso]EMM386.EXE [ON|OFF|AUTO] [memoria] [MIN=dim] [W=ON|W=OFF] [Mx|FRAME=indirizzo|/Pmmmm] [Pn=indirizzo] [X=mmmm-nnnn] [I=mmmm-nnnn] [B=indirizzo] [L=minXMS] [A=regalt] [H=handle] [D=nnn] [RAM=mmmm-nnnn] [NOEMS] [NOVCPI] [HIGHSCAN] [VERBOSE] [WIN=mmmm-nnnn] [NOHI] [ROM=mmmm-nnnn] [NOMOVEXBDA] [ALTBOOT] [NOBACKFILL] Opzioni. [unità:][percorso] Specifica la posizione del file Emm386.exe. [ON|OFF|AUTO] Attiva il driver della periferica EMM386 se impostato a ON o sospende il driver EMM386 se impostato a OFF oppure imposta il driver EMM386 alla modalità automatica se impostato ad AUTO. La modalità automatica attiva il supporto della memoria espansa e il supporto dei blocchi della memoria superiore solo su richiesta di un’applicazione. Il valore predefinito è ON. Utilizzare il comando EMM386 per modificare questo valore una volta che EMM386 è stato avviato. memoria Specifica la quantità massima di memoria estesa in KB che EMM386 deve fornire come memoria EMS/VCPI. Questa quantità è aggiunta alla memoria utilizzata per i blocchi di memoria superiore e per lo stesso EMM386. Il valori per “memoria” sono compresi tra 64 e il valore minore tra 32768 e la quantità di memoria estesa disponibile quando EMM386 è caricato. Il valore predefinito è la quantità di memoria estesa disponibile. Se si specifica NOEMS, il valore predefinito sarà 0. EMM386 arrotonda il valore per difetto al precedente multiplo di 16. MIN=dim Specifica la quantità minima di memoria EMS/VCPI in KB che sarà fornita da EMM386, se quella quantità è disponibile. EMM386 riserva questa quantità di memoria estesa da utilizzare come memoria EMS/VCPI quando è caricato tramite il comando DEVICE=EMM386.EXE nel file CONFIG.SYS. È possibile che EMM386 fornisca ulteriore memoria EMS/VCPI fino alla quantità specificata dal parametro “memoria” se è disponibile sufficiente memoria XMS quando un’applicazione richiede della memoria EMS/VCPI. I valori sono compresi tra zero e il valore specificato dal parametro “memoria”. Il valore predefinito è 256. Se si specifica NOEMS, il valore predefinito sarà 0. Se il valore di MIN è maggiore del valore di “memoria”, EMM386 utilizzerà il valore specificato da MIN. W=ON|W=OFF Attiva o disattiva il supporto per il coprocessore Weitek. L’impostazione predefinita è W=OFF. Mx Specifica l’indirizzo del frame di pagina. I valori validi per “x” sono compresi tra 1 e 14. Nel seguente elenco è indicato ciascun valore e l’indirizzo di base associato in formato esadecimale. 1 => C000H 8 => DC00H 2 => C400H 9 => E000H 3 => C800H 10 => 8000H 4 => CC00H 11 => 8400H 5 => D000H 12 => 8800H 6 => D400H 13 => 8C00H MS-DOS um 125 di 138 7 => D800H 14 => 9000H I valori compresi tra 10 e 14 devono essere utilizzati solo su PC che dispongono di 512 KB di memoria. FRAME=indirizzo Specifica direttamente la base di un segmento di frame di pagina. Per impostare uno specifico indirizzo di base di segmento, utilizzare l’opzione FRAME, quindi specificare l’indirizzo desiderato. I valori validi per l’indirizzo sono compresi tra 8000H e 9000H e tra C000H e E000H, con incrementi di 400H. Per fornire memoria espansa e disattivare il frame di pagina, è possibile specificare FRAME=NONE. Quest’impostazione può tuttavia impedire il corretto funzionamento di alcune applicazioni che richiedono l’utilizzo della memoria espansa. /Pmmmm Specifica l’indirizzo del frame di pagina. I valori validi per mmmm sono compresi tra 8000H e 9000H e tra C000H e E000H, con incrementi di 400H. Pn=indirizzo Specifica l’indirizzo di un segmento di una pagina specifica, dove n è il numero della pagina specificata e indirizzo è l’indirizzo del segmento desiderato. I valori validi per n sono compresi tra 0 e 255. Quelli per indirizzo sono compresi tra 8000H e 9C00H e tra C000H e EC00H, con incrementi di 400H. Gli indirizzi per le pagine da 0 a 3 devono essere contigui al fine di mantenere la compatibilità con la versione 3.2 delle specifiche per la memoria espansa LIM EMS. Se si utilizza l’opzione “Mx”, FRAME o “/Pmmmm”, non sarà possibile specificare gli indirizzi per le pagine da 0 a 3 per l’opzione “/Pmmmm”. X=mmmm-nnnn Impedisce a EMM386 di utilizzare un particolare intervallo d’indirizzi di segmenti per una pagina EMS o per i blocchi di memoria superiore. I valori validi per mmmm e nnnn sono compresi tra A000H e FFFFH e sono arrotondati per difetto al precedente limite di 4 KB. L’opzione X ha la precedenza sull’opzione I se i due intervalli si sovrappongono. I=mmmm-nnnn Specifica un intervallo d’indirizzi di segmenti da utilizzare per una pagina EMS o per i blocchi di memoria superiore. I valori validi per mmmm e nnnn sono compresi tra A000H e FFFFH e sono arrotondati per difetto al precedente limite di 4 KB. L’opzione X ha la precedenza sull’opzione I se i due intervalli si sovrappongono. B=indirizzo Specifica l’indirizzo di segmento più basso disponibile per il banking della memoria espansa swapping di 16 KB di pagine. I valori validi sono compresi tra 1000H e 4000H, il valore predefinito è 4000H. l=minXMS fa sì che la quantità di memoria espansa specificata in KB sia ancora disponibile dopo il caricamento di EMM386. Il valore predefinito è 0. A=regalt Specifica la quantità di set di registri a rapido avvicendamento utilizzati per la funzionalità multitasking che è possibile allocare a EMM386. I valori validi sono compresi tra 0 e 254. Il valore predefinito è 7. Ciascun set di registri aggiunge circa 200 byte alle dimensioni di EMM386 in memoria. H=handle Specifica la quantità di handle che possono essere utilizzati da EMM386. I valori validi sono compresi tra 2 e 255. Il valore predefinito è 64. D=nnn Specifica la quantità di KB di memoria che deve essere riservata per l’accesso diretto alla memoria DMA bufferizzato. A parte il DMA del disco floppy, questo valore deve riflettere il maggiore trasferimento DMA che sarà eseguito mentre EMM386 è attivo. I valori validi per nnn sono compresi tra 16 e 256. Il valore predefinito è 32. MS-DOS um 126 di 138 RAM=mmmm-nnnn Specifica un intervallo d’indirizzi di segmenti da utilizza re per i blocchi di memoria superiore. Inoltre, attiva il supporto EMS. Se non è specificato alcun intervallo, EMM386 utilizzerà tutto lo spazio disponibile della scheda per creare i blocchi di memoria superiore e un frame di pagina per l’EMS. NOEMS Fornisce l’accesso all’area della memoria superiore ma impedisce di accedere alla memoria espansa. NOVCPI Disattiva il supporto per le applicazioni VCPI. Quest’opzione deve essere utilizzata insieme all’opzione NOEMS. Se NOVCPI è specificata senza l’opzione NOEMS, EMM386 non disattiverà il supporto per la VCPI. Se sono specificate entrambe le opzioni, EMM386 ignorerà il parametro memoria e l’opzione MIN. La disattivazione del supporto per le applicazioni VCPI riduce la quantità di memoria estesa allocata. HIGHSCAN Specifica che EMM386 effettua un ulteriore controllo per determinare la disponibilità di memoria superiore da utilizzare come blocchi di memoria superiore o finestre EMS. Su alcuni PC, l’utilizzo di quest’opzione può non avere alcun effetto o far sì che EMM386 consideri disponibili delle aree di memoria superiore che in realtà non lo sono. In questo caso, è possibile che il sistema si arresti. VERBOSE fa sì che EMM386 visualizzi dei messaggi di errore o di stato durante il caricamento. In base all’impostazione predefinita, EMM386 visualizza dei messaggi solo nel caso in cui si verifichi una condizione di errore. È possibile abbreviare VERBOSE a V. Per visualizzare i messaggi di stato senza aggiungere l’opzione VERBOSE, premere e tenere premuto ALT mentre EMM386 è avviato. WIN=mmmm-nnnn Riserva l’intervallo d’indirizzi di segmenti specificato per Windows anziché per EMM386. I valori validi per mmmm e nnnn sono compresi tra A000H e FFFFH e sono arrotondati per difetto al precedente limite di 4 KB. L’opzione X ha la precedenza sull’opzione WIN se i due intervalli si sovrappongono. L’opzione WIN ha la precedenza sulle opzioni RAM, ROM e I se i rispettivi intervalli si sovrappongono. [NOHI] non consente il caricamento di EMM386 nell’area di memoria superiore. In genere, parte di EMM386 è caricata nella memoria superiore. L’utilizzo di quest’opzione riduce la memoria convenzionale disponibile e aumenta l’area di memoria superiore disponibile per gli UMB. [ROM=mmmm-nnnn] Specifica un intervallo di indirizzi di segmenti che EMM386 utilizza per la RAM shadow, memoria ad accesso casuale utilizzata per la ROM. I valori validi per mmmm e nnnn sono compresi tra A000H e FFFFH e sono arrotondati per difetto al precedente limite di 4 KB. L’utilizzo di quest’opzione può rendere il sistema più veloce se questo non dispone già di RAM shadow. [NOMOVEXBDA] Impedisce a EMM386 di spostare i dati del BIOS esteso dalla memoria convenzionale a quella superiore. [ALTBOOT] Specifica che EMM386 utilizza un handler alternativo per riavviare il sistema quando è premuto CTRL+ALT+CANC. Utilizzare quest’opzione solo se il sistema si arresta o funziona in modo non corretto dopo che è stato caricato EMM386 e si è premuto CTRL+ALT+CANC. [NOBACKFILL] se EMM386 è configurato per fornire i blocchi di memoria superiore utilizzando l’opzione NOEMS o RAM, EMM386 riempirà automaticamente di nuovo la memoria convenzionale fino a 640 KB. MS-DOS um 127 di 138 Tuttavia, poiché Windows non supporta questo tipo di operazione, sarà necessario utilizzare l’opzione NOBACKFILL se il PC in uso dispone di meno di 640 KB di memoria convenzionale. HIMEM.SYS HIMEM è un gestore della memoria estesa, un’utility che coordina l’utilizzo della memoria estesa del PC, inclusa HMA, in modo che due applicazioni o due driver di periferica non utilizzino contemporaneamente la stessa memoria. HIMEM è installato aggiungendo il comando DEVICE per il file HIMEM.SYS nel file CONFIG.SYS. La riga di comando per HIMEM.SYS deve precedere qualsiasi comando che avvia applicazioni o driver di periferica che utilizzano la memoria estesa. Ad esempio, la riga di comando per HIMEM.SYS deve precedere quella per EMM386.EXE. DEVICE=[unità:][percorso]HIMEM.SYS [/A20CONTROL:ON|OFF] [/CPUCLOCK:ON|OFF] [/EISA] [/HMAMIN=m] [/INT15=xxxx] [/MACHINE:xxxx] [/NOABOVE16] [/NOEISA] [/NUMHANDLES=n] [/SHADOWRAM:ON|OFF] [/TESTMEM:ON|OFF] [/VERBOSE] [/X] Nella maggior parte dei casi, non sarà necessario specificare delle opzioni della riga di comando. I valori predefiniti per HIMEM.SYS sono studiati per funzionare con la maggior parte dell’H/W. [unità:][percorso] Specifica la posizione del file HIMEM.SYS che deve sempre trovarsi sulla stessa unità che contiene i file di MS-DOS. Se il file si trova nella cartella principale dell’unità di avvio, non sarà necessario includere alcun percorso. Sarà comunque necessario includere il nome di file completo. /A20CONTROL:ON|OFF Specifica se HIMEM deve controllare la riga A20 anche se tale riga era attiva nel momento in cui HIMEM è stato caricato. L’handler A20 forisce l’accesso all’HMA. Se è specificato /A20CONTROL:OFF, HIMEM controllerà la riga A20 solo se A20 era disattivata quando HIMEM è stato caricato, il valore predefinito è il seguente. /A20CONTROL:ON. /CPUCLOCK:ON|OFF Specifica se HIMEM deve influire sulla velocità dell’orologio del PC. Se la velocità dell’orologio cambia quando s’installa HIMEM, sarà possibile correggere il problema specificando /CPUCLOCK:ON. Se è attivata quest’opzione, sarà tuttavia rallentato HIMEM. Il valore predefinito è /CPUCLOCK:OFF. /EISA Specifica che HIMEM deve allocare tutta la memoria estesa disponibile. Quest’opzione è necessaria solo sui PC EISA (Extended Industry Standard Architecture) con più di 16 MB di memoria. Sugli altri PC, HIMEM alloca automaticamente tutta la memoria estesa disponibile. /HMAMIN=m Specifica la quantità di memoria richiesta da un’applicazione perché HIMEM gli consenta l’uso dell’HMA. L’HMA può essere utilizzata da una sola applicazione alla volta. HIMEM alloca l’HMA alla prima applicazione che dispone dei requisiti di utilizzo della memoria impostati per quest’opzione. È possibile specificare un valore compreso tra 0 e 63. Impostare /HMAMIN alla quantità di memoria richiesta dall’applicazione che utilizza la quantità maggiore di memoria HMA. L’opzione /HMAMIN non è necessaria, il valore predefinito è infatti 0. Se si omette quest’opzione o la s’imposta a 0, HIMEM allocherà l’HMA alla prima applicazione che la richiede, indipendentemente dalla quantità che sarà effettivamente MS-DOS um 128 di 138 utilizzata. L’opzione /HMAMIN non ha alcun effetto quando Windows è eseguito in modalità 386 avanzata. /INT15=xxxx alloca la quantità di memoria estesa in KB che deve essere riservata all’interfaccia dell’Interrupt 15H. Alcune precedenti applicazioni allocano la memoria estesa utilizzando questa interfaccia al posto del metodo XMS fornito da HIMEM. Se si utilizzano queste applicazioni, è possibile garantirsi una quantità sufficiente di memoria disponibile impostando “xxxx” a 64 KB in più rispetto alla quantità richiesta dalle applicazioni. È possibile specificare un valore compreso tra 64 e 65535. Tuttavia, non è possibile specificare più memoria di quanta il sistema ne abbia a disposizione. Se è specificato un valore minore di 64, il valore diventerà pari a 0. Il valore predefinito è 0. /MACHINE:xxxx Specifica il tipo di PC in uso. In genere, HIMEM è in grado di rilevare il tipo di PC, tuttavia esistono alcuni PC che non è possibile rilevare. Su questi sistemi, HIMEM utilizza il tipo predefinito, IBM AT o compatibile. È possibile che sia necessario includere l’opzione /MACHINE se il PC in uso è di un tipo che HIMEM non è in grado di rilevare e se HIMEM non funziona correttamente con impostato il tipo di sistema predefinito. /NOABOVE16 Specifica di non utilizzare il supporto INT 15H AX==E801H Compaq Bigmem per l’analisi della memoria estesa. /NOEISA Specifica che HIMEM non deve eseguire l’analisi EISA per la memoria estesa. /NUMHANDLES=n specifica il numero massimo di handle ai blocchi di memoria estesa EMB che possono essere utilizzati contemporaneamente. È possibile specificare un valore compreso tra 1 e 128. Il valore predefinito è 32. Ciascun handle aggiuntivo richiede altri 6 byte di memoria. L’opzione /NUMHANDLES non ha alcun effetto quando Windows è eseguito in modalità 386 avanzata. /SHADOWRAM:ON|OFF Specifica se disattivare la RAM shadow SHADOWRAM:OFF o se lasciarla attivata SHADOWRAM:ON. Alcuni PC rendono l’esecuzione del codice ROM più veloce tramite il shadowing nella RAM, vale a dire copiando all’avvio il codice ROM nella più veloce memoria RAM, che utilizza la memoria estesa. Sui PC che utilizzano la RAM shadow e dispongono di meno di 2 MB di RAM, HIMEM in genere tenta di disattivare la RAM shadow per recuperare della memoria estesa aggiuntiva per Windows. HIMEM è in grado di disattivare la RAM shadow solo su certi tipi di sistemi. Quando HIMEM disattiva la RAM shadow, il codice ROM è eseguito nella memoria ROM anziché nella RAM, che è più veloce. Per questo motivo, il PC sarà leggermente più lento di prima. /TESTMEM:ON|OFF Determina se HIMEM esegue una verifica della memoria quando è avviato il PC. In base all’impostazione predefinita, HIMEM verifica l’affidabilità della memoria estesa del PC ad ogni avvio del PC. Questa verifica consente d’identificare la memoria che non è più affidabile e che può determinare l’instabilità del sistema o la perdita di dati. La verifica eseguita da HIMEM è più completa di quella standard che è eseguita all’accensione nella maggior parte dei PC. Per evitare la verifica di HIMEM, specificare /TESTMEM:OFF. La disattivazione della verifica della memoria abbrevia il processo di avvio del sistema. MS-DOS um 129 di 138 L’impostazione predefinita è /TESTMEM:ON. /VERBOSE Fa sì che HIMEM visualizzi dei messaggi di errore o di stato durante il caricamento. In base all’impostazione predefinita, HIMEM visualizza dei messaggi solo nel caso in cui si verifichi una condizione di errore. È possibile abbreviare VERBOSE a V. Per visualizzare i messaggi di stato senza aggiungere l’opzione VERBOSE, premere e tenere premuto ALT mentre HIMEM è avviato. /X Specifica di non utilizzare INT 15H AX==E820H, l’API di supporto alla memoria estesa. RAMDRIVE.SYS Utilizza parte della RAM del PC per simulare un’unità disco rigido. Questo driver della periferica deve essere caricato tramite un comando DEVICE o DEVICEHIGH nel file CONFIG.SYS. Le unità RAM sono molto più veloci delle unità disco rigido in quanto il PC può leggere le informazioni più velocemente dalla memoria che dal disco rigido. Un’unità RAM si presenta come una normale unità disco rigido e può essere utilizzata come una qualsiasi unità disco rigido. La differenza più importante fra questi due tipi di unità consiste nel fatto che l’unità RAM esiste solo nella memoria. Le informazioni contenute in un’unità RAM sono perse ogni volta che si spegne o si riavvia il PC. È possibile creare quante unità RAM si desidera, fino ad utilizzare tutta la memoria disponibile sul PC. A tal fine, aggiungere una riga RAMDRIVE.SYS nel file CONFIG.SYS per ciascuna unità RAM aggiuntiva desiderata. DEVICE=[unità:][percorso]RAMDRIVE.SYS [DimDisco DimSettore [Numvoci]]][/E | /A] Opzioni. [unità:][percorso] Specifica la posizione del file RAMDRIVE.SYS. DimDisco specifica la quantità di KB di memoria che si desidera utilizzare per l’unità RAM. Ad esempio, per creare un’unità RAM da 640 KB, occorrerà specificare 640. Se non è specificato alcun valore, RAMDRIVE creerà un’unità RAM da 64 KB. È possibile specificare un valore compreso tra 4 e 32767. Non è in ogni caso possibile specificare una quantità di memoria superiore a quella disponibile nel sistema. DimSettore specifica la dimensione in byte dei settori del disco. La dimensione può essere uguale a 128, 256 o 512 byte. Se è specificato un valore per DimSettore, sarà necessario specificarlo anche per DimDisco. In genere, è utilizzata la dimensione predefinita di 512 byte. NumVoci limita il numero di file e di cartelle che è possibile creare nella cartella principale dell’unità RAM. Il limite varia da 2 a 1024 voci. Il limite che è specificato è arrotondato per eccesso al successivo limite di dimensione dei settori. Se non è specificato alcun limite, sarà possibile creare fino a 64 voci nella cartella principale dell’unità RAM. Se è specificato un valore per NumVoci, sarà necessario specificarlo anche per DimDisco e DimSettore. Se non si dispone di memoria sufficiente per creare l’unità RAM come specificato, RAMDRIVE tenterà di crearla con il limite di 16 voci di directory. L’unità RAM sarà creata, ma probabilmente avrà un limite diverso da quello desiderato. MS-DOS um 130 di 138 /E Crea l’unità RAM nella memoria estesa. Affinché RAMDRIVE utilizzi la memoria estesa, è necessario che il PC sia configurato adeguatamente e che nel file CONFIG.SYS il comando DEVICE per il gestore della memoria estesa quale HIMEM.SYS preceda il comando DEVICE relativo a RAMDRIVE.SYS. In genere, è meglio creare un’unità RAM nella memoria estesa se questa è disponibile su PC in uso. /A Crea l’unità RAM nella memoria espansa. Affinché RAMDRIVE utilizzi la memoria espansa, è necessario che il PC sia configurato adeguatamente e che nel file CONFIG.SYS il comando DEVICE per il gestore della memoria espansa quale EMM386, 386MAX, CEMM o QEMM preceda il comando DEVICE relativo a RAMDRIVE.SYS. SETVER.EXE Carica in memoria la tabella della versione di MS-DOS. Questo driver deve essere caricato utilizzando un comando DEVICE o DEVICEHIGH nel file CONFIG.SYS. SETVER.EXE carica in memoria la tabella della versione di MS-DOS, nella quale sono elencati i nomi delle applicazioni e il numero di versione di MS-DOS con cui ciascuna applicazione deve essere eseguita. DEVICE=[unità:][percorso]SETVER.EXE Opzioni. [unità:][percorso] Specifica la posizione del file SETVER.EXE. ACCDATE Per ciascun disco rigido, specificare se deve essere registrata la data in cui è stato eseguito l’ultimo accesso ai file. Le date di accesso sono disattivate per tutte le unità quando il PC è avviato in modalità provvisoria. In base all’impostazione predefinita, le date non sono registrate per i dischi floppy. ACCDATE=unità1+|- [unità2+|-] Opzioni. Il segno più (+) indica che la data dell’ultimo accesso ai file sull’unità deve essere memorizzata. Il segno meno (-) indica che la data dell’ultimo accesso ai file non deve essere memorizzata. BREAK Imposta o disattiva la funzionalità estesa di CTRL+C. Questo comando può essere digitato al prompt dei comandi o utilizzato nel file CONFIG.SYS. È possibile premere CTRL+C per arrestare un’applicazione o un’operazione ad esempio, l’ordinamento di file. In genere, MS-DOS verifica CTRL+C solo quando legge dalla tastiera o scrive sullo schermo o su una stampante. Se s’imposta BREAK a ON, la funzionalità CTRL+C sarà estesa anche ad altre funzioni, quali le operazioni di lettura e scrittura di un disco. BREAK [ON|OFF] MS-DOS um 131 di 138 Per visualizzare l’impostazione corrente di BREAK al prompt dei comandi, utilizzare la seguente sintassi: BREAK. Nel file CONFIG.SYS, utilizzare invece la seguente sintassi: BREAK=ON|OFF. ON| OFF Attiva o disattiva la funzionalità estesa CTRL+C. BUFFERS/BUFFERSHIGH Alloca memoria per un numero specificato di buffer su disco all’avvio del sistema. Utilizzare il comando BUFFERSHIGH per caricare i buffer nella memoria superiore. Questi comandi possono essere utilizzati solo nel file CONFIG.SYS. BUFFERS=n[,m] BUFFERSHIGH=n[,m] Opzioni. n Specifica il numero di buffer su disco. Il valore di n deve essere compreso tra 1 e 99. Il valore predefinito è 30. m specifica il numero di buffer presenti nella cache secondaria. Il valore di m deve essere compreso tra 0 e 8. Il valore predefinito è 0 vale a dire, nessun buffer nella cache secondaria. Se è specificato un valore non valido per n o m, sarà utilizzata automaticamente l’impostazione predefinita. COUNTRY Consente a MS-DOS di utilizzare le convenzioni specifiche di un paese per la visualizzazione della data, dell’ora e della valuta; per determinare l’ordine con cui i caratteri sono ordinati e per determinare quali caratteri possono essere utilizzati nei nomi di file. Questo comando può essere utilizzato solo nel file CONFIG.SYS. Il comando COUNTRY configura MS-DOS in modo che riconosca il set di caratteri e le convenzioni di punteggiatura specifici della lingua selezionata. COUNTRY=xxx[,[yyy][,[unità:][percorso]nomefile]] Opzioni. xxx Specifica il codice del paese. yyy Specifica il set di caratteri per il paese. [unità:][percorso]nomefile Specifica la posizione e il nome del file che contiene le informazioni sul paese. DEVICE Carica in memoria il driver della periferica specificato. Questo comando può essere utilizzato solo nel file CONFIG.SYS. DEVICE=[unità:][percorso]nomefile [parametri-dp] Opzioni. [unità:][percorso]nomefile Specifica la posizione e il nome del driver della periferica da caricare. [parametri-dp] Specifica qualsiasi informazione sulla riga di comando richiesta dal driver della periferica. DEVICEHIGH Carica nella memoria superiore il driver della periferica specificato. MS-DOS um 132 di 138 Questa operazione consente di rendere disponibili ulteriori byte nella memoria convenzionale, che possono essere utilizzati per altre applicazioni. Se non è disponibile spazio nella memoria superiore, il comando DEVICEHIGH avrà la stessa funzione del comando DEVICE. Questo comando può essere utilizzato solo nel file CONFIG.SYS. DEVICEHIGH [unità:][percorso]nomefile [parametri-dp] Per specificare l’area o le aree di memoria in cui caricare il driver della periferica, utilizzare la seguente sintassi. DEVICEHIGH [[/L:area1[,dimmin1][;area2[,dimmin2] [/S]]= [unità:][percorso]nomefile [parametri-dp] Opzioni. [unità:][percorso]nomefile Specifica la posizione e il nome del driver della periferica da caricare nella memoria superiore. parametri-dp Specifica qualsiasi informazione sulla riga di comando richiesta dal driver della periferica. /L:area1[,dimmin1][;area2[,dimmin2] Specifica una o più aree di memoria nelle quali caricare il driver della periferica. In base all’impostazione predefinita, MS-DOS carica il driver nel blocco di memoria superiore più grande disponibile UMB e rende tutti gli altri blocchi di memoria superiore disponibili per l’utilizzo del driver. È possibile utilizzare l’opzione /L per caricare il driver della periferica in una specifica area di memoria oppure indicare le aree che il driver può utilizzare. Per caricare il driver nel blocco più grande di un’area specifica della memoria superiore, specificare il numero dell’area dopo l’opzione /L. Ad esempio, per caricare il driver nel blocco dell’area 4, sarà necessario digitare /L:4. Per visualizzare l’elenco delle aree di memoria disponibili, digitare MEM /F al prompt dei comandi. Quando è caricato utilizzando l’opzione /L, il driver della periferica può utilizzare solo l’area di memoria specificata. Alcuni driver utilizzano più aree di memoria, quindi è necessario specificare le aree. Per sapere come la memoria è utilizzata da un driver, digitare il comando MEM /M e specificare il nome del driver come argomento. Per specificare due o più aree, separare i numeri dei blocchi con un punto e virgola (;). Ad esempio, per utilizzare i blocchi 2 e 3, sarà necessario digitare /L:2;3. In genere, MS-DOS carica un driver in un blocco di memoria superiore nell’area specificata solo se l’area contiene un blocco più grande delle dimensioni di caricamento del driver, che in genere corrispondono alle dimensioni del file eseguibile. Se il driver in esecuzione richiede più memoria di quando è caricato, sarà possibile utilizzare il parametro dimmin per assicurarsi che il driver non sia caricato in un blocco di memoria superiore troppo piccolo. Se si specifica un valore per il parametro dimmin, MS-DOS caricherà il driver in quell’area solo se questa contiene un blocco di memoria superiore più grande delle dimensioni di caricamento del driver e del valore di dimmin. /S Riduce alle dimensioni minime il blocco di memoria superiore durante il caricamento del driver. Questa opzione consente un utilizzo più efficiente della memoria. È in genere utilizzata solo dall’utility MEMMAKER, che analizza l’utilizzo della memoria per un driver di periferica per determinare se l’opzione /S può essere utilizzata per il caricamento del driver. Questa opzione può essere utilizzata solo insieme all’opzione /L e interessa solo i blocchi MS-DOS um 133 di 138 di memoria superiore per i quali è stata specificata una dimensione minima. DOS Specifica che MS-DOS deve mantenere un collegamento all’area di memoria superiore, deve essere in parte caricato nell’area di memoria alta HMA o in entrambe. Questo comando può essere utilizzato solo nel file CONFIG.SYS. DOS=HIGH|LOW[,UMB|,NOUMB][,AUTO|,NOAUTO] DOS=[HIGH,|LOW,]UMB|NOUMB[,AUTO|,NOAUTO] DOS=[HIGH,|LOW,][UMB,|NOUMB,]AUTO|NOAUTO Opzioni. UMB|NOUMB Specifica se MS-DOS deve gestire i blocchi di memoria superiore creati da un provider di questi tipi di blocchi, quale EMM386.EXE. Il parametro UMB specifica che gli eventuali blocchi devono essere gestiti da MS-DOS. Il parametro NOUMB specifica che MS-DOS non deve gestire i blocchi di memoria superiore. L’impostazione predefinita è NOUMB. HIGH|LOW Specifica se una parte di MS-DOS deve essere caricata nell’area di memoria alta (HIGH) o se MS-DOS deve rimanere interamente nella memoria convenzionale (LOW). L’impostazione predefinita è LOW. AUTO|NOAUTO Specifica se i driver di periferica HIMEM.SYS, IFSHLP.SYS, DBLBUFF.SYS e SETVER.EXE devono essere automaticamente caricati da MS-DOS, se non sono esplicitamente caricati nel file CONFIG.SYS. L’impostazione predefinita AUTO carica automaticamente i driver. L’impostazione AUTO utilizza inoltre automaticamente i comandi BUFFERSHIGH, FILESHIGH, FCBSHIGH, LASTDRIVEHIGH e STACKSHIGH, indipendentemente dall’utilizzo della forma -HIGH del comando. Se si specifica il parametro NOAUTO, sarà necessario caricare esplicitamente i driver di periferica e utilizzare la forma -HIGH dei comandi appena indicati per ottenere le migliori prestazioni. DRIVPARM Definisce i parametri per le periferiche, quali le unità disco o le unità nastro quando è avviato MS-DOS. Questo comando può essere utilizzato solo nel file CONFIG.SYS. Il comando DRIVPARM modifica i parametri dell’unità fisica esistente. Non crea una nuova unità logica. Le impostazioni specificate nel comando DRIVPARM ignorano le definizioni del driver per qualsiasi periferica a blocchi precedente. DRIVPARM=/D:numero [/C] [/F:fattore] [/H:intestazioni] [/I] [/N] [/S:settori] [/T:tracce] Opzioni. /D:numero Specifica il numero dell’unità fisica. I valori per numero devono essere compresi tra 0 e 255 ad esempio, il numero 0 = unità A, 1 = unità B, 2 = unità C. /C Specifica che l’unità è in grado di rilevare se la porta dell’unità è chiusa. /F:fattore Specifica il tipo di unità. Nella tabella che segue sono elencati i valori validi per fattore e delle brevi descrizioni per ciascuno di essi. Il valore predefinito è 2. 0 160 KB/180 KB o 320 KB/360 KB. MS-DOS um 134 di 138 1 1.2 MB. 2 720 KB. 5 Disco rigido 6 Nastro. 7 1.44 MB. 8 Disco ottico di lettura e scrittura. 9 2.88 MB. /H:intestazioni Specifica il numero massimo d’intestazioni. I valori per intestazioni devono essere compresi tra 1 e 99. Il valore predefinito dipende dal valore specificato per /F:fattore. /I Specifica un’unità disco da 3”½ elettronicamente compatibile. Le unità elettronicamente compatibili sono installate sul PC e utilizzano il controller esistente dell’unità disco floppy. Utilizzare l’opzione /I se il BIOS ROM non supporta le unità disco floppy da 3”½. /N Specifica una periferica a blocchi non removibile. /S:settori Specifica il numero di settori per traccia supportato dalla periferica a blocchi. I valori per settori devono essere compresi tra 1 e 99. Il valore predefinito dipende dal valore specificato per /F:fattore. /T:tracce Specifica il numero di tracce per lato supportato dalla periferica a blocchi. Il valore predefinito dipende dal valore specificato per /F:fattore. FCBS, FCBSHIGH Specifica il numero di blocchi di controllo file FCB che possono essere aperti da MS-DOS contemporaneamente. Utilizzare il comando FCBSHIGH per caricare i blocchi di controllo file nella memoria superiore. Questi comandi possono essere utilizzati solo nel file CONFIG.SYS. Un blocco di controllo file è una struttura di dati in cui sono memorizzate le informazioni per un file. FCBS=x FCBSHIGH=x Opzioni. x Specifica il numero di blocchi di controllo file che possono essere aperti in MS-DOS contemporaneamente. I valori validi per x sono compresi tra 1 e 255. Il valore predefinito è quattro. FILES/FILESHIGH Specifica il numero di file a cui MS-DOS può accedere contemporaneamente. Utilizzare il comando FILESHIGH per caricare il comando nell’area di memoria superiore. Questi comandi possono essere utilizzati solo nel file CONFIG.SYS. FILES=x FILESHIGH=x Opzioni. x Specifica il numero di file a cui MS-DOS può accedere contemporaneamente. I valori validi per x sono compresi tra 8 e 255. Il valore predefinito è 8. INSTALL/INSTALLHIGH Carica in memoria un’applicazione residente in memoria quando è avviato MS-DOS. MS-DOS um 135 di 138 Utilizzare il comando INSTALLHIGH per caricare l’applicazione residente in memoria nella memoria superiore. Questi comandi possono essere utilizzati solo nel file CONFIG.SYS. Le applicazioni residenti in memoria rimangono in memoria fintanto che il PC è acceso. Possono essere utilizzate anche quando sono in esecuzione altre applicazioni. È possibile utilizzare il comando INSTALL o INSTALLHIGH per caricare applicazioni MSDOS residenti in memoria, quali FASTOPEN, KEYB, NLSFUNC E SHARE. INSTALL=[unità:][percorso]nomefile [parametri-comando] INSTALLHIGH=[unità:][percorso]nomefile [parametri-comando] Opzioni. [unità:][percorso]nomefile Specifica la posizione e il nome dell’applicazione residente in memoria che si desidera eseguire. parametri-comando Specifica i parametri per l’applicazione specificata per nomefile. LASTDRIVE/LASTDRIVEHIGH Specifica il numero massimo di unità a cui è possibile accedere. Utilizzare il comando LASTDRIVEHIGH per caricare la struttura dei dati LASTDRIVE nella memoria superiore. Questi comandi possono essere utilizzati solo nel file CONFIG.SYS. Il valore che è specificato rappresenta l’ultima unità valida che MS-DOS deve riconoscere. LASTDRIVE=x LASTDRIVEHIGH=x Opzioni. x Specifica una lettera di unità compresa tra A e Z. NUMLOCK Specifica se il tasto BLOC NUM è attivato o meno all’avvio del PC. Questo comando può essere utilizzato solo nel file CONFIG.SYS. NUMLOCK=[ON|OFF] Opzioni. ON|OFF Se è impostato a ON, attiva il tasto BLOC NUM quando in MS-DOS è visualizzato il menu di avvio, se è impostato a OFF, disattiva BLOC NUM. REM Consente d’includere dei commenti in un file batch o nel file CONFIG.SYS. Il comando REM è inoltre utile per disattivare dei comandi. Nel file CONFIG.SYS è possibile utilizzare un punto e virgola (;) al posto del comando REM. Questa operazione non può invece essere applicata ai file batch. REM [stringa] Opzioni. stringa Specifica una stringa di caratteri: il comando che si desidera disattivare o il commento che si desidera includere. SET Visualizza, imposta o rimuove le variabili di ambiente MS-DOS. MS-DOS um 136 di 138 Le variabili di ambiente servono a controllare il comportamento di alcuni file batch e applicazioni e a controllare la visualizzazione e il funzionamento di MS-DOS. Il comando SET è spesso utilizzato nel file AUTOEXEC.BAT o CONFIG.SYS per impostare le variabili di ambiente ogni volta che è avviato MS-DOS. SET variabile=[stringa] Per visualizzare le impostazioni correnti di ambiente al prompt dei comandi, utilizzare la seguente sintassi: SET. variabile specifica la variabile che si desidera impostare o modificare. stringa specifica la stringa che si desidera associare alla variabile specificata. SHELL Specifica il nome e la posizione dell’interprete dei comandi che deve essere utilizzato da MS-DOS. Questo comando può essere utilizzato solo nel file CONFIG.SYS. Se si desidera utilizzare un proprio interprete dei comandi al posto di COMMAND.COM, sarà possibile specificarne il nome aggiungendo un comando SHELL nel file CONFIG.SYS. SHELL=[[unità:]percorso]nomefile [parametri] Opzioni. [[unità:]percorso]nomefile Specifica la posizione e il nome dell’interprete dei comandi che deve essere utilizzato da MS-DOS. parametri Specifica i parametri o le opzioni della riga di comando che possono essere utilizzate con l’interprete specificato. STACKS/STACKSHIGH Supporta l’utilizzo dinamico degli stack di dati per la gestione degli interrupt H/W. Utilizzare il comando STACKSHIGH per caricare gli stack nella memoria superiore. Questi comandi possono essere utilizzati solo nel file CONFIG.SYS. STACKS=n,s STACKSHIGH=n,s Opzioni. n Specifica il numero degli stack. I valori validi per n sono 0 e i numeri compresi tra 8 a 64. s Specifica le dimensioni in byte di ciascuno stack. I valori validi per s sono 0 e i numeri compresi tra 32 e 512. SWITCHES Specifica opzioni speciali in MS-DOS. Questo comando può essere utilizzato solo nel file CONFIG.SYS. SWITCHES= /F /K /N /E[:n] Opzioni. /F Evita la pausa di due secondi successiva alla visualizzazione del messaggio che informa dell’avvio di MS-DOS. /K Fa sì che una tastiera avanzata si comporti come una convenzionale. /N Impedisce l’utilizzo di F5 o di F8 per ignorare i comandi di avvio. Se si utilizza il comando SWITCHES /N, sarà ancora possibile premere CTRL+F5 o MS-DOS um 137 di 138 CTRL+F8 per ignorare DRVSPACE.BIN oppure DBLSPACE.BIN. Per evitare ciò, utilizzare il comando D**SPACE /SWITCHES per aggiungere l’impostazione SWITCHES /N nel file D**SPACE.INI. /E[:n] Utilizzata senza il parametro :n, questa opzione indica che IO.SYS deve disattivare il riposizionamento automatico di EBIOS. Il riposizionamento automatico di EBIOS aumenta la memoria convenzionale disponibile per le applicazioni per MS-DOS. La disattivazione di questa funzionalità determina una riduzione della memoria convenzionale disponibile per le applicazioni per MS-DOS. Utilizzare l’opzione /E con i parametro n per riposizionare N byte di EBIOS nella memoria bassa, dove n è il numero di byte da riposizionare. Il valore minimo per n è 48 e il massimo è 1024. Il numero specificato è sempre arrotondato per eccesso al successivo multiplo di 16. Prompt dei comandi Visualizzazione delle cartelle dal prompt dei comandi. Per visualizzare il contenuto di una cartella in formato finestra dal prompt dei comandi, digitare. Start. oppure Start... Avvio di applicazioni per Windows dal prompt dei comandi. Per avviare un’applicazione per Windows dal prompt dei comandi, digitare il nome dell’applicazione specificando i parametri necessari. Ad esempio, per avviare il Blocco note, digitare NOTEPAD al prompt dei comandi, quindi premere INVIO. Per avviare un’applicazione o aprire un documento, è possibile utilizzare il comando Start. Esempio. C:>start Nomedoc.est. MS-DOS um 138 di 138 UBERTINI MASSIMO http://www.ubertini.it [email protected] Dip. Informatica Industriale I.T.I.S. "Giacomo Fauser" Via Ricci, 14 28100 Novara Italy tel. +39 0321482411 fax +39 0321482444 http://www.fauser.edu [email protected]
© Copyright 2024 Paperzz