1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
| puts macro string ;вывод строки
lea dx,string
mov ah,09h
int 21h
endm
.model tiny
.code
org 100h
.386
start:
jmp inst
Unloaded db 'Drvinfo BblgPyGen$'
AlreadyLoaded
db 13,10,'Drvinfo 6blJl 3agPygeH PaHee',13,10,'$'
inputdrv db 'BBeDuTe 6yKBy DucKa: $'
drv db 0 ;номер диска
wrongdrv db 13,10,'HevePHblu DucK.',13,10,'$'
rp1 db 13,10,'DucK :'
db 13,10,'O6`em: $'
rp2 db ' 6auT'
db 13,10,'CBo6oDHo: $'
rp3 db ' 6auT'
db 13,10,'Байт на сектор: $'
rp4 db 13,10,'Секторов на кластер: $'
rp5 db 13,10,'Количество копий FAT: $'
rp6 db 13,10,'Количество каталогов в корне диска: $'
rp7 db 13,10,'Количество секторов в одной копии FAT: $'
anykey db 13,10,'Нажмите любую клавишу для продолжения$'
Sucsess db 13,10,'Drvinfo загружен',13,10,'$'
ctrl db 0 ;признак нажатой клавиши ctrl 0-отжата, ff - нажата
Old2D dd ? ; резервируем место для адреса оригинального обработчика прерывания 2Dh
Old09 dd ? ; резервируем место для адреса оригинального обработчика прерывания 09h
scrbuf db 4000 dup (0) ;Область памяти для сохранения текстового экрана
old_f dw 0 ;Регистр флагов работающей программы
mode db 0 ;режим работы программы 0 - фоновый 1- полноэкранный
curpos dw 0 ;текущее положение курсора.
inp db 6,7 dup(0) ;строка, куда вводится время будильника с клавиатуры.
New2DObrab proc ; новый обработчик прерывания int2Dh
cli ; запретить обработку маскированных прерываний (сброс флага прерывания if=0)
pushf
cmp al,98h ; проверка на то, загружен ли резидент?
jne ex_c ; нет - пропускаем
inc al ; устанавливаем al=99h - признак того, что резидент загружен
ex_c: popf ; восстановить флаги
sti ; разрешить прерывния
iret ; выход из прерывания
DoNothing:
popf
sti ; установка флага прерывания if в единицу
jmp dword ptr CS:[Old2D] ;переход на реальный обработчик прерывания
endp
New09Obrab proc ; новый обработчик прерывания int09h
pushf ; заносим флаги в стек, поскольку iret в конце оригинального обработчика заберет один экземпляр флагов из стека
call dword ptr CS:[Old09] ; вызов оригинального обработчика
cli ; запретить прерывания
pusha ; сохранить регистры общего назначения
push es ; сохраняем сегментные регистры, поскольку они не сохраняются командой pusha
push ds
push cs ;ds=cs
pop ds
in al,60h ; читаем из порта клавиатуры скан-код нажатой клавиши
cmp al,1dh ; если нажат CTRL
jnz m1
mov cs:ctrl,1 ;то устанавливаем флаг
m1: cmp al,9dh ; если отжат CTRL
jnz m2
mov cs:ctrl,0 ;то сбрасываем флаг
m2: cmp al,2dh ;нажата X
jnz ne_x ;если нет, то пропустить
cmp cs:ctrl,0 ;если ctrl не нажата, то пропустить
jz ne_x
;Нажаты Ctrl+X - выгружаем резидент
push 0b800h ;Сегмент видеопамяти
pop es
mov bx,1920 ;адрес в видеопамяти куда будем выводить сообщение(средняя строка, начало)
lea si,Unloaded ;выводимое сообщение
mov ah,7 ;серый цвет
outt: mov al,cs:[si] ;берем символ сообщения
cmp al,'$' ;если признак конца строки
jz outex ;то закончить
mov es:[bx],ax ;выводим прямо в видеопамять
inc si ;следующий символ
add bx,2
jmp outt ;продолжаем ввывод
outex:
push 0 ;сегмент векторов прерываний
pop es
mov ax,word ptr CS:Old09 ; восстановление векторов прерываний
mov es:[24h],ax
mov ax,word ptr CS:Old09+2
mov es:[26h],ax
mov ax,word ptr CS:Old2d
mov es:[0b4h],ax
mov ax,word ptr CS:Old2d+2
mov es:[0b6h],ax
mov ax,CS:[2Ch] ; сегмент переменных окружения
dec ax ;его MCB
mov es,ax
mov es:[1],word ptr 0 ;Записываем блока Owner=0, значит блок свободен
mov ax,CS ; сегмент самого резидента
dec ax ;его MCB
mov es,ax
mov es:[1],word ptr 0 ;Записываем блока Owner=0, значит блок свободен
jmp skipwork
ne_x: cmp al,1Fh ;нажата S
jnz skipwork ;если нет, то пропустить
cmp cs:ctrl,0 ;если ctrl не нажата, то пропустить
jz skipwork
jmp newmode ;Переход если Ctrl+S
skipwork:
pop ds ; восстанавливаем сегментные регистры
pop es
popa ; восстанавливаем регистры общего назначения
sti ; разрешить прерывания
iret ; выход из прерывания
;Начинаем запуск программы
newmode:
mov al,mode
cmp al,1 ;программа уже активирована?
jz skipwork ;если да, то просто прыгаем на реальный обработчик таймера
mov mode,1 ;программа активирована
push bp ; Теперь сохраняем адрес возврата в текущую прогамму
mov bp,sp
mov ax,[bp+22]
mov old_ip,ax
mov ax,[bp+24]
mov old_cs,ax
mov ax,[bp+26]
mov old_f,ax ; и ее флаги, чтобы когда мы закроем информацию о диске, можно было вернуться в программу пользователя
mov word ptr [bp+22],offset infomode ;подменяем в стеке адрес возврата из прерывания на адрес программы ввода диска
mov [bp+24],cs
pop bp
jmp skipwork ;завершаем прерывание
infomode: ;Режим
push es ;Сохраняем регистры
push ds
pushad
push cs ; настраиваем регистр данных
pop ds
mov ah,0fh
int 10h
cmp al,03 ;Текущий режим экрана текстовый?
jnz bad_mode ;если нет - то не запускаем
mov ax,0b800h ;Сегмент экранной памяти для прямого доступа
mov es,ax
mov cx,2000
lea si,scrbuf ;Сохраняем экран в зарезервированный буфер
xor di,di
zz1: mov ax,es:[di]
mov [si],ax
inc si
inc si
inc di
inc di
loop zz1
mov cx,2000 ;очищаем экран
xor di,di
mov ax,0f20h
repnz stosw
push cs ;es=cs
pop es
mov ah,3
mov bh,0
int 10h ;берем текущие координаты курсора
mov curpos,dx ;сохраняем их
mov dx,0
mov ah,2
int 10h ;устанавливаем курсор в верхний левый угол
inpdrv:
puts inputdrv ;выводим сообщение с просьбой ввести букву диска
mov ah,1
int 21h ;ожидаем ввода символа с клавиатуры
and al,1fh ;оставляем только младшие биты символа(номер диска 1-A,2-B...)
test al,al ;если это ноль(расширенный код)
jnz cont2
mov ah,1 ;то читаем второй код расширенного кода
int 21h ;из буфера клавиатуры
jmp inpdrv ;и просим снова ввести букву диска
cont2: mov drv,al ;сохраняем номер диска
mov dl,al
add al,40h ;преобразуем номер диска в букву
mov rp1+7,al ;добавляем ее в сообщение
mov ah,32h ;Функция получения параметров диска
int 21h ;получаем параметры диска
cmp al,0ffh ;если ff - значит такого диска нет
jnz cont1
puts wrongdrv ;выводим ошибку
jmp inpdrv ;и просим ввести диск заново
cont1: push ds
pop es ;es=ds
push cs
pop ds ;ds=cs
push bx ;сохраняем смещение адреса блока данных о диске
puts rp1 ;выводим первое сообщение
mov ah,36h ;информация о размере диска
mov dl,drv ;номер диска
int 21h ;получаем информацию о размере
; INT 21 - DISK SPACE
; AH = 36H
; DL = DRIVE NUMBER (1-4)
; Return: AX = ? (SIDES)
; BX = ? (BLOCKS FREE)
; CX = ? (BLOCK SIZE)
; DX = ? (TOTAL BLOCKS)
;NOTE: MULT AX x CX x BX for FREE SPACE ON DISK
;MULT AX x CX x DX for TOTAL DISK SPACE
movzx eax,ax ;расширяем полученные параметры до 32 бит
movzx ebx,bx
movzx ecx,cx
movzx edx,dx
push eax ;сохраняем параметры
push ebx
push ecx
mul edx ;AX x CX x DX for TOTAL DISK SPACE
mul ecx ;в eax получаем размер диска
call printdec32 ;выводим его на экран
puts rp2 ;выводим второе сообщение
pop ecx ;восстанавливаем данные о размере диска
pop ebx
pop eax
mul ebx ;MULT AX x CX x BX for FREE SPACE ON DISK
mul ecx ;получаем свободный объем
call printdec32 ;выводим его на экран
puts rp3 ;выводим третье сообщение
pop bx ;восстанавливаем адрес блока данных(полных адрес находится в es:bx)
mov ax,es:[bx+2];берем из блока количество байт на сектор
call printdec ;выводим на экран
puts rp4 ;выводим 4-е сообщение
movzx ax, byte ptr es:[bx+4];берем из блока количество секторов в кластере
call printdec ;выводим на экран
puts rp5 ;выводим 5-е сообщение
movzx ax, byte ptr es:[bx+8];берем из блока количество копий FAT
call printdec ;выводим на экран
puts rp6 ;выводим 6-е сообщение
mov ax, es:[bx+9] ;берем из блока количество копий FAT
call printdec ;выводим на экран
puts rp7 ;выводим 7-е сообщение
movzx ax, byte ptr es:[bx+15] ;берем из блока количество секторов в одной копии FAT
call printdec ;выводим на экран
puts anykey ;выводим сообщение с просьбой о нажатии любой клавиши
mov ah,0
int 16h ;ожидаем нажатия любой клавиши
back: push 0b800h
pop es
mov cx,2000 ;восстанавливаем экран
lea si,scrbuf
xor di,di
repnz movsw
mov ah,2
mov bh,0
mov dx,curpos
int 10h ;восстанавливаем прежнее положение курсора
bad_mode:
mov mode,0 ;фоновый режим
push [old_f] ;восстанавливаем флаги
popf
popad ; восстанавливаем регистры
pop ds ; помещаем значение регистра ds в стек
pop es ; записываем в es число из стека
;возвращаемся к прерванной программе
db 0EAh ; опкод far jump
old_ip dw 0 ;на прерванную программу пользователя
old_cs dw 0
endp
;преобразование числа из ах в десятичную систему и вывод
printdec proc ;преобразование и вывод числа из ах
;ax - число
push cx ;сохраняем регистры
push dx
push bx
push si
xor si,si ;обнуляем флаг отрицательного числа
mov bx,10 ;основание системы
XOR CX,CX ;в сх будет количество цифр в десятичном числе
test ax,ax ;число отрицательное
jns @@m1 ;если да
neg ax ;то меняем знак
inc si ;устанавливаем признак отрицательности
@@m1: XOR dx,dx
DIV bx ;делим число на степени 10
PUSH DX ;и сохраняем остаток от деления(коэффициенты при степенях) в стек
INC CX
TEST AX,AX
JNZ @@m1
test si,si ;если число отрицательное
jz @@m22
push -3 ;то в начале ставим знак минус
inc cx
@@m22: mov ah,2
@@m2: POP DX
ADD DL,'0' ;преобразовываем число в ASCII символ
int 21h ;выводим его
LOOP @@m2 ;все цифры
pop si
pop bx ;восстанавливаем регистры
POP dx
POP cx
RET
printdec endp
printdec32 proc ;преобразование числа из ах в десятичную строку по адресу es:di
;eax - число
push ecx ;сохраняем регистры
push edx
push ebx
mov ebx,10 ;основание системы
XOR ecx,ecx ;в сх будет количество цифр в десятичном числе
@m1: XOR edx,edx
DIV ebx ;делим число на степени 10
PUSH edx ;и сохраняем остаток от деления(коэффициенты при степенях) в стек
INC ecx
TEST eax,eax
JNZ @m1
mov ah,2
@m2: POP edx
ADD DL,'0' ;преобразовываем число в ASCII символ
int 21h
LOOP @m2 ;все цифры
pop ebx ;восстанавливаем регистры
POP edx
POP ecx
RET
printdec32 endp
inst: ; загрузка резидента
; оставляем резидент в памяти
NoParameters:
mov AL,98h ; загружен ли резидент?
int 2Dh ; Служебное прерывание
cmp AL,99h
je TSRAlreadyLoaded; выход, чтобы избежать повторной загрузки
mov ax,3509h ; GetVector
int 21h
mov word ptr Old09,BX
mov word ptr Old09+2,ES
mov ax,2509h ; SetVector
mov dx,offset New09Obrab
int 21h
mov ax,352Dh ; GetVector
int 21h
mov word ptr Old2D,BX
mov word ptr Old2D+2,ES
mov ax,252Dh ; SetVector
mov dx,offset New2DObrab
int 21h
puts Sucsess ; сообщение об успехе
mov dx,(inst-start+100h); указываем системе сколько памяти в параграфах занимает наш резидент
int 27h ; закончить, но остаться в памяти
TSRAlreadyLoaded:
puts AlreadyLoaded ;Резидент уже загружен
Quit:
mov ah,4ch ; стандартный выход из программы
int 21h
end start |