L'accesso all'I/O, con la scusa del beep
Se occorre inviare un beep all'operatore, tramite la console, e' sufficiente inviare in output il carattere BEL, codice Ascii 07h, come nel semplicissimo esempio sottostante.
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; beep_1.asm ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ;compilare con nasm+gcc global main ;necessario per il linker gcc extern printf section .data beep db 07h,0 section .text main: push dword beep ;Passa il Ptr Stringa call printf add esp,4 ;Riallinea lo Stack ret ;EOF ::::::::::::::::::::::::::::::::::::::
Ma se non ci accontentiamo del segnale acustico predefinito e ne vogliamo uno di frequenza e durata variabili ? A questo punto risulta evidente che il beep e' la scusa per parlare di I/O. Per raggiungere l'obiettivo faremo uso del terzo timer programmabile presente nell'8253 che fara' giungere un segnale alla frequenza desiderata all'altoparlante, che verra' abilitato tramite l'8255. Tutto fattibile, se il controllo dell'hardware fosse sotto il nostro totale controllo. Eppure la possibilita' esiste, basta chiedere il permesso al S.O. per lavorare a livello di root. Pertanto il nostro esempio, su macchine Intel compatibili, realizzera' i seguenti punti:
Il listato e' abbastanza lineare, ma alcuni passaggi richiedono la conoscenza dei byte di programmazione per l'8253 e le connessioni hardware tra 8255, 8253 ed altoparlante.
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; beep_2.asm ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ;compilare con nasm+gcc %macro @ioperm 3 mov ebx,%1 ;;Numero porto iniziale; mov ecx,%2 ;;Quantita' di porti in successione mov edx,%3 ;;Richiesta: 1=Abilitazione, 0=Revoca mov eax,101 ;;Funzione sys_call=ioperm int 80h or eax,eax ;;Test esito: "jns okay" %endmacro global main ;necessario per il linker gcc extern usleep, printf section .data msgerr db "NON abilitato all'uso dei porti di I/O! " db "Occorrono i privilegi di ROOT.",0Ah db "Oppure si e' verificato un ERRORE nel caso " db "si sia in ROOT.",7,0Ah,0 durata dd 200000 section .text main: @ioperm 61h,1,1 ;Richiesta Permesso 8255 I/O 61h jns okay1 jmp err okay1: @ioperm 42h,2,1 ;Richiesta Permesso 8253 I/O 42h e 43h jns okay2 jmp err okay2: in al,61h ;Abilita altoparlante or al,3 out 61h,al mov al,0B6h ;Programmazione timer 8253 out 43h,al mov ax,0800h ;Impostazione costante di frequenza out 42h,al mov al,ah out 42h,al push dword [durata] ;Imposta durata in microsecondi call usleep add esp,4 ;Riallinea lo Stack in al,61h ;Disabilita altoparlante and al,0FCh out 61h,al jmp exit err: push dword msgerr ;Passa il Ptr Stringa call printf add esp,4 ;Riallinea lo Stack exit: @ioperm 42h,2,0 ;Revoca Permessi I/O @ioperm 61h,1,0 ret ;EOF :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Lo schema seguente aiuta a capire alcuni passaggi relativi alle istruzioni di in e di out presenti nel programma. Come si vede, l'uscita dell'altoparlante e' condizionata sia dal segnale di out dell'8253 sia dal bit 1 del porto B 8255. A sua volta l'8253 viene abilitato al suo gate dal bit 0 del porto B 8255. Pertanto e' necessario che i 2 bit 0,1 del porto B 8255 siano alti per abilitare l'uscita del segnale sull'altoparlante (vedi or al,3), e siano invece bassi per bloccare il segnale (vedi and al,0FCh) alla fine.
Mentre la programmazione del timer avviene in due fasi. Prima viene fissato il modo operativo dell'8253 tramite il Registro di controllo che ha sede nel Porto 43h; per funzionare come generatore di frequenza occorre inviare il byte B6h (vedi documentazione Intel). Quindi, per fissare la frequenza di funzionamento, viene inviata una word tramite il Porto 42h, e cio' si realizza con due operazioni di out, un byte alla volta.
Niente può danneggiare un uomo salvo se stesso. Niente può essere rubato all'uomo. Ciò che realmente l'uomo possiede è ciò che è in lui. Ciò che ne è al di fuori è cosa senza importanza.
Oscar Wilde