Programowanie: Program odporny na RESET
From Atariki
Uodpornienie programu na wciśnięcie klawisza RESET realizowane jest zależnie od tego, w jaki sposób program jest ładowany do pamięci komputera.
Spis treści |
BOOT
Program ładowany z nośnika za pośrednictwem procedury BOOT otrzymuje sterowanie w dwóch momentach:
1. Po załadowaniu wszystkich sektorów/rekordów programu określonych w nagłówku BOOT.
Wywoływana jest wtedy procedura inicjalizacji umiejscowiona pod adresem BOOT_ADDRESS+6. Ta procedura wywoływana jest jednorazowo w całym procesie BOOT i jest to dobre miejsce do inicjalizacji danych, które nie będą inicjalizowane po wykonaniu RESET-u. Ponieważ długość programu bootowalnego ograniczona jest do 256 sektorów/rekordów, jest to również dobre miejsce do załadowania pozostałej części programu do pamięci. Jeśli proces inicjalizacji przebiegł poprawnie, procedura powinna zakończyć się ze skasowanym znacznikiem C. Ustawiony znacznik C przy wyjściu z procedury skutkuje zgłoszeniem błędu BOOT ERROR i powtórką (lub, w przypadku magnetofonu, zakończeniem) procesu BOOT-owania.
2. Po zainicjalizowaniu programu.
Adres startu programu, umiejscowiony pod adresem BOOT_ADDRESS+4, przepisywany jest do DOSINI ($0C), jeśli BOOT odbywał się z dysku, lub do CASINI ($02) jeśli BOOT-owano z kasety, i jest to automatycznie adres, pod który system operacyjny będzie przekazywał kontrolę programowi po naciśnięciu klawisza RESET.
Nie należy ingerować w zawartość rejestru BOOT? ($09), gdyż jest on ustawiany przez system operacyjny.
Wektor inicjalizacji DOSINI/CASINI może zostać wykorzystany do natychmiastowego uruchomienia programu, lub też do jego inicjalizacji i ustawienia wektora DOSVEC ($0A), do którego sterowanie przekazywane jest przez procedurę RESET po całkowitym zakończeniu jej działania. W ten sposób instaluje się w systemie DOS.
Wektor DOSVEC jest ustawiany przez OS w początkowej fazie procedury RESET na adres wejścia do SELF-TEST, więc jeżeli z procedury DOSINI/CASINI powrócimy do systemu nie ustawiwszy wektora DOSVEC, wtedy OS na końcu odda sterowanie właśnie tam.
Wektor DOSVEC służy również do przekazania sterowania po wydaniu komendy "DOS" BASIC-a, oraz jest ogólnie wektorem wskazującym procedurę uruchomienia programu powłoki (zazwyczaj Command Processor lub Menu DOS-a).
Przykładowy program bootujący:
DOSVEC = $a prog = $2000 opt h- o+ org prog ;nagłówek boot .byte 0 ;flaga boot - nieużywana przez system (niektóre DOS-y ustawiają tu swój identyfikator) .byte count ;ilość sektorów boot .word prog ;adres ładowania .word start ;adres uruchomienia programu init: ;tu można zainicjalizować dane nie inicjalizowane po RESET ... clc rts start: ;a tu zainicjalizować dane inicjalizowane po RESET ... ;i przejąć sterowanie ... ;lub ewentualnie zapisać DOSVEC ldx #<run ldy #>run stx DOSVEC sty DOSVEC+1 ;i wrócić do systemu rts run: ;a to się będzie wykonywać po zakończeniu BOOT-a lub po wydaniu polecenia DOS z BASIC-a ... len = *-prog count = (len+127)/128 ;obliczenie ilości sektorów boot - ceil(len/128)
DOS
Program pracujący pod kontrolą jakiegokolwiek DOS-u nie jest odporny na wciśnięcie klawisza RESET. Zostaje on wtedy przerwany, a kontrola przekazywana jest bezpośrednio do DOS-u.
Aby uodpornić taki program na RESET wykorzystuje się tradycyjny mechanizm inicjalizowania systemu.
Odbywa się to poprzez tzw. przedłużenie wektora DOSINI/CASINI, dzięki czemu przed inicjalizacją własnego programu ma szanse zainicjalizować się DOS oraz programy TSR zainstalowane w systemie wcześniej.
Format nierelokowalny (zgodny z AtariDOS)
Programy w tradycyjnym formacie binarnym nie są relokowalne.
Niezależnie od rodzaju DOS-u, przez który są uruchamiane, przedłużanie wektora CASINI/DOSINI odbywa się w taki sam sposób:
CASINI = 2 BOOT? = 9 DOSVEC = $a DOSINI = $c prog = $2000 opt h+ o+ org prog init: jsr prolong ;w przypadku TSR można tutaj podnieść MEMLO ... ;tutaj wykonujemy program główny ... ;po czym przy wyjściu z programu przywracamy zawartość wektora lda BOOT? ldx #0 ;BOOT z kasety (przywracamy CASINI=$02) cmp #2 beq @+ ldx #10 ;BOOT z dysku (przywracamy DOSINI=$0C) @ lda init+1 ldy init+2 sta CASINI,x sty CASINI+1,x jmp (DOSVEC) prolong: ;a to wykona się tylko raz po uruchomieniu programu przez DOS lda BOOT? ldx #0 ;BOOT z kasety (przedłużamy CASINI=$02) cmp #2 beq @+ ldx #10 ;BOOT z dysku (przedłużamy DOSINI=$0C) @ lda CASINI,x ldy CASINI+1,x sta init+1 sty init+2 lda #<init ldy #>init sta CASINI,x sty CASINI+1,x rts run init
Format relokowalny (SpartaDOS X)
SpartaDOS X definiuje specjalny relokowalny format pliku binarnego. Pozwala on dodatkowo na wykorzystanie symboli oraz rezerwacje pamięci.
Przedłużenie wektora DOSINI następuje tu analogicznie jak w przypadku programów nierelokowalnych. Okazuje się jednak, że to nie wystarcza do poprawnego uruchomienia programu po wciśnięciu RESET, ponieważ podczas wywoływania łańcucha inicjalizującego poprzednio zainstalowane w systemie programy, DOS przejmuje kontrolę i nie wraca do procedury inicjującej program.
Zapobiega temu wyzerowanie zmiennej COMTAB+$20 (nieoficjalnie zwanej DOSFLG) w fazie inicjalizacji. Gdy odporność na RESET stanie się niepotrzebna (np. tuż przed zakończeniem programu), zmienną tę należy ustawić na dowolną ujemną wartość.
Ponieważ SDX nie obsługuje magnetofonu, można darować sobie rozpoznawanie rodzaju BOOT-a i aktualizację CASINI, a skoncentrować się wyłącznie na DOSINI.
Przykładowy program relokowalny (dla SpartaDOS X):
DOSVEC = $a DOSINI = $c COMTAB smb 'COMTAB ' opt h+ o+ blk reloc main init: jsr prolong ... ;tutaj wykonujemy program główny ... ;po czym przy wyjściu z programu przywracamy zawartość wektora ldx init+1 ldy init+2 stx DOSINI sty DOSINI+1 lda #$ff sta COMTAB+$20 jmp (DOSVEC) prolong: ;a to wykona się tylko raz po uruchomieniu programu przez DOS ldx DOSINI ldy DOSINI+1 stx init+1 sty init+2 ldx initad ldy initad+1 stx DOSINI sty DOSINI+1 lda #0 sta COMTAB+$20 rts initad .word init