Programowanie: Program odporny na RESET
From Atariki
Wersja z dnia 22:37, 18 paź 2013 Mono (Dyskusja | wkład) ← Previous diff |
Wersja z dnia 00:40, 19 paź 2013 Mono (Dyskusja | wkład) (unifikacja procedur dla formatow nierelokowalnych; linki; styl.) Next diff → |
||
Linia 27: | Linia 27: | ||
Przykładowy program bootujący: | Przykładowy program bootujący: | ||
<pre> | <pre> | ||
+ | DOSVEC = $a | ||
+ | |||
prog = $2000 | prog = $2000 | ||
Linia 40: | Linia 42: | ||
init: | init: | ||
;tu można zainicjalizować dane nie inicjalizowane po RESET | ;tu można zainicjalizować dane nie inicjalizowane po RESET | ||
+ | ... | ||
clc | clc | ||
rts | rts | ||
start: | 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 i po wydaniu polecenia DOS z BASIC-a | ||
... | ... | ||
Linia 50: | Linia 67: | ||
</pre> | </pre> | ||
- | = AtariDOS = | + | = DOS = |
- | Standardowy program pracujący pod kontrolą DOS-u nie jest odporny na wciśnięcie klawisza RESET, a więc po jego wciśnięciu kontrola zostaje przekazana do DOS-u. | + | 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 systemowy mechanizm inicjalizowania systemu: | + | Aby uodpornić taki program na RESET wykorzystuje się tradycyjny mechanizm inicjalizowania systemu. |
- | 1. Poprzez wektor DOSINI/CASINI inicjalizuje się programy TSR i sterowniki zainstalowane w systemie i rozszerzające jego działanie. | + | 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. |
- | Odbywa się to poprzez tzw. przedłużenie wektora DOSINI/CASINI dzięki czemu przed inicjalizacją własnego programu mają szanse zainicjalizować się DOS oraz programy TSR zainstalowane w systemie wcześniej. | + | == Format nierelokowalny (zgodny z AtariDOS) == |
- | 2. Poprzez wektor DOSVEC oddaje się sterowanie do programu, który ma być docelowo uruchomiony po RESET. | + | Programy w [[Binarny plik DOSu|tradycyjnym formacie binarnym]] nie są relokowalne. |
- | Odbywa się to przez zapisanie wektora DOSVEC w procedurze inicjalizacji uruchamianej przez DOSINI/CASINI. | + | Niezależnie od rodzaju DOS-u przez który są uruchamiane przedłużanie wektora CASINI/DOSINI odbywa się w taki sam sposób: |
+ | <pre> | ||
+ | CASINI = 2 | ||
+ | BOOT? = 9 | ||
+ | DOSVEC = $a | ||
+ | DOSINI = $c | ||
- | Standardowo DOS podczas własnej procedury inicjalizacyjnej zapisuje tu adres programu DUP.SYS lub CP.SYS. | ||
- | |||
- | Programy TSR zazwyczaj potrzebują jedynie zainicjalizować swoje działanie i wykorzystują jedynie DOSINI/CASINI nie zapisując wektora DOSVEC. | ||
- | |||
- | Przykładowy fragment programu odpornego na RESET: | ||
- | <pre> | ||
prog = $2000 | prog = $2000 | ||
Linia 77: | Linia 93: | ||
init: | init: | ||
jsr prolong | jsr prolong | ||
- | ldx DOSVEC | ||
- | ldy DOSVEC+1 | ||
- | stx olddosvec | ||
- | sty olddosvec+1 | ||
- | ldx #<start | ||
- | ldy #>start | ||
- | stx DOSVEC | ||
- | sty DOSVEC+1 | ||
;w przypadku TSR można tutaj podnieść MEMLO | ;w przypadku TSR można tutaj podnieść MEMLO | ||
... | ... | ||
Linia 92: | Linia 100: | ||
;tutaj wykonujemy program główny | ;tutaj wykonujemy program główny | ||
... | ... | ||
- | ;po czym przy wyjściu z programu przywracamy zawartości wektorów | + | ;po czym przy wyjściu z programu przywracamy zawartość wektora |
- | ldx olddosvec | + | |
- | ldy olddosvec+1 | + | |
- | stx DOSVEC | + | |
- | sty DOSVEC+1 | + | |
lda BOOT? | lda BOOT? | ||
ldx #0 ;BOOT z kasety (przywracamy CASINI=$02) | ldx #0 ;BOOT z kasety (przywracamy CASINI=$02) | ||
Linia 124: | Linia 128: | ||
sty CASINI+1,x | sty CASINI+1,x | ||
rts | rts | ||
- | |||
- | olddosvec .ds 2 | ||
run init | run init | ||
</pre> | </pre> | ||
- | = SpartaDOS X = | + | == Format relokowalny (SpartaDOS X) == |
- | Generalnym imperatywem jest zakaz modyfikowania zawartości wektora DOSVEC (!), gdyż zawiera on adres bazowy dla różnych zmiennych DOS-a. | + | [[SpartaDOS X]] definiuje specjalny [[COM#SpartaDOS X|relokowalny format pliku binarnego]]. Pozwala od 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 się po wciśnięciu RESET, ponieważ podczas wywoływania łańcucha inicjalizującego poprzednio zainstalowane w systemie programy DOS nie wraca na powrót do naszej procedury inicjalizującej. | ||
+ | Zapobiega temu wyzerowanie zmiennej COMTAB+$20 (nieoficjalnie zwanej DOSFLG) w fazie inicjalizacji. | ||
+ | Po zakończeniu programu należy ją ustawić na dowolną ujemną wartość. | ||
Ponieważ SDX nie obsługuje magnetofonu, darujemy sobie rozpoznawanie rodzaju BOOT-a i aktualizację CASINI - skoncentrujemy się wyłącznie na DOSINI. | Ponieważ SDX nie obsługuje magnetofonu, darujemy sobie rozpoznawanie rodzaju BOOT-a i aktualizację CASINI - skoncentrujemy się wyłącznie na DOSINI. | ||
- | == Program nierelokowalny == | + | Przykładowy program relokowalny (dla SpartaDOS X): |
- | + | ||
- | Bazujemy na systemowym mechanizmie i modyfikujemy jedynie wektor DOSINI/CASINI. | + | |
- | + | ||
- | Przykładowy program nierelokowalny uruchamiany komendą X (dla AtariDOS): | + | |
<pre> | <pre> | ||
- | prog = $2000 | + | DOSINI = $c |
- | opt h+ o+ | + | COMSPEC smb 'COMSPEC ' |
- | org prog | + | |
- | 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 | ||
- | rts | ||
- | |||
- | prolong: | ||
- | ;a to wykona się tylko raz po uruchomieniu programu przez DOS | ||
- | ldx DOSINI | ||
- | ldy DOSINI+1 | ||
- | stx init+1 | ||
- | sty init+2 | ||
- | ldx #<init | ||
- | ldy #>init | ||
- | stx DOSINI | ||
- | sty DOSINI+1 | ||
- | rts | ||
- | |||
- | run init | ||
- | </pre> | ||
- | |||
- | == Program relokowalny == | ||
- | |||
- | Okazuje się, że to jednak nie wystarcza żeby relokowalny program dla SpartaDOS X mógł poprawnie uodpornić się na RESET, ponieważ podczas wywoływania łańcucha inicjalizującego poprzednio zainstalowane w systemie programy DOS nie wraca na powrót do naszej procedury inicjalizującej, a skacze bezpośrednio przez DOSVEC. | ||
- | Zapobiega temu wyzerowanie zmiennej COMTAB+$20 (nieoficjalnie zwanej DOSFLG) - po zakończeniu programu należy ustawić w niej dowolną ujemną wartość. | ||
- | |||
- | Przykładowy program relokowalny (dla SpartaDOS X): | ||
- | <pre> | ||
opt h+ o+ | opt h+ o+ | ||
blk reloc main | blk reloc main | ||
Linia 217: | Linia 184: | ||
= Linki = | = Linki = | ||
- | [[BOOT (format pliku)]] | + | * [[BOOT (format pliku)|Format BOOT]] |
+ | * [[Binarny plik DOSu|Format binarnego pliku DOS]] | ||
+ | * [[COM#SpartaDOS X|Format binarnego pliku SpartaDOS X]] | ||
[[Kategoria:Programowanie Atari 8-bit]] | [[Kategoria:Programowanie Atari 8-bit]] | ||
[[Kategoria:Niezbędnik kodera]] | [[Kategoria:Niezbędnik kodera]] |
Wersja z dnia 00:40, 19 paź 2013
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 RESETu. Ponieważ długość programu bootowalnego ograniczona jest do 255 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 głoszeniem błędu BOOT ERROR i zakończeniem procesu BOOTowania.
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 BOOTowano 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.
Jeżeli z procedury DOSINI/CASINI powrócimy do systemu nie ustawiwszy wektora DOSVEC, wtedy OS ustawi tam adres procedury SELF TEST.
Wektor DOSVEC służy również do przekazania sterowania po wydaniu komendy DOS BASIC-a.
Przykładowy program bootujący:
DOSVEC = $a prog = $2000 opt h- o+ org prog ;nagłówek boot .db 0 ;flaga boot - nieużywana przez system (niektóre DOS-y ustawiają tu swój identyfikator) .db count ;ilość sektorów boot .dw prog ;adres ładowania .dw 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 i 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 ... rts start: ;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 od 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 się po wciśnięciu RESET, ponieważ podczas wywoływania łańcucha inicjalizującego poprzednio zainstalowane w systemie programy DOS nie wraca na powrót do naszej procedury inicjalizującej. Zapobiega temu wyzerowanie zmiennej COMTAB+$20 (nieoficjalnie zwanej DOSFLG) w fazie inicjalizacji. Po zakończeniu programu należy ją ustawić na dowolną ujemną wartość.
Ponieważ SDX nie obsługuje magnetofonu, darujemy sobie rozpoznawanie rodzaju BOOT-a i aktualizację CASINI - skoncentrujemy się wyłącznie na DOSINI.
Przykładowy program relokowalny (dla SpartaDOS X):
DOSINI = $c COMSPEC smb 'COMSPEC ' 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 COMSPEC+$20 rts 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 COMSPEC+$20 rts initad .dw init