CodeNet / Языки программирования / Ассемблер / Пишем "многозадачную" ОС в "Real Mode"
CodeNet / Платформы / Пишем ОС / Пишем "многозадачную" ОС в "Real Mode"
CodeNet / Платформы / Пишем ОС / Пишем "многозадачную" ОС в "Real Mode"
Модуль mtasks.asm
Установка новых прерываний, реализация многозадачности.
;# Тут мы получаем старые вектора ############################################ PROC getvectors ; Сохраняем 08h и 20h прерывания IFDEF GlukOS ;--- Для ГлюкОСы call _di push ds xor bx,bx mov ds,bx mov bx,[ds:0020h] mov es,[ds:0022h] mov [cs:oldseg08],es mov [cs:oldofs08],bx mov bx,[ds:0080h] mov es,[ds:0082h] mov [cs:oldseg20],es mov [cs:oldofs20],bx pop ds call _ei ret ELSE ;--- Для ДОСа mov ah,035h mov al,008h int 021h mov [cs:oldseg08],es mov [cs:oldofs08],bx mov ah,035h mov al,020h int 021h mov [cs:oldseg20],es mov [cs:oldofs20],bx ret ENDIF ;--- GlukOS ENDP getvectors ;# Тут мы вешаем новые - свои прерывания ##################################### PROC setvectors ; Вешаемся на 08h и 20h прерывания IFDEF GlukOS ;--- Для ГлюкОСы call _di push ds xor bx,bx mov ds,bx lea bx,[cs:kernel] mov [ds:0020h],bx mov [ds:0022h],cs lea bx,[newint20] mov [ds:0080h],bx mov [ds:0082h],cs pop ds call _ei ret ELSE ;--- Для ДОСа push ds mov ax,cs mov ds,ax lea dx,[kernel] mov ah,025h mov al,008h int 021h ; Вешаемся на 20h прерывание mov ax,cs mov ds,ax lea dx,[newint20] mov ah,025h mov al,020h int 021h pop ds ret ENDIF ;--- GlukOS ENDP setvectors ;# Тут мы восстанавливаем старoе прерывания ################################## PROC restorevectors ; Восстанавлмваем 08h и 20h прерывания IFDEF GlukOS ;--- Для ГлюкОСы call _di push ds xor bx,bx mov ds,bx mov es,[cs:oldseg08] mov bx,[cs:oldofs08] mov [ds:0020h],bx mov [ds:0022h],es mov es,[cs:oldseg20] mov bx,[cs:oldofs20] mov [ds:0080h],bx mov [ds:0082h],es pop ds call _ei ret ELSE ;--- Для ДОСа push ds mov ax,[cs:oldseg08] mov ds,ax mov dx,[cs:oldofs08] mov ah,025h mov al,008h int 021h mov ax,[cs:oldseg20] mov ds,ax mov dx,[cs:oldofs20] mov ah,025h mov al,020h int 021h pop ds ret ENDIF ;--- GlukOS ENDP restorevectors ; # Переменные в кодовом сегменте ############################################ oldofs08 DW ? oldseg08 DW ? oldofs20 DW ? oldseg20 DW ? int08 DW 1 ; Стоит ли переключать задачи ??? ; # Разрешаем переключать задачи ############################################# PROC _ei mov [Word Ptr cs:int08],1 ret ENDP _ei ; # Запрещаем переключать задачи ############################################# PROC _di mov [Word Ptr cs:int08],0 ret ENDP _di ;# Прерывание 020h ########################################################### PROC newint20 ; Прерывание 020h (выгрузка задачи) call _di pop ax ;¬ pop ax ;¦ Достаем всякое дерьмо из стека pop ax ;+ push cs pop ds lea di,[cs:firsttask] ; DI = Адрес начала структуры TTASK mov al,[cs:numtask] ; AL = Номер задачи xor ah,ah ; AX = Номер задачи push dx mov dx,515 mul dx ; AX = Смещения от начала firsttask pop dx add di,ax ; DI = Абсолютное смещение вершины ; стека в структуре TTASK mov [Byte Ptr cs:di],255 mov dx,[cs:di+3] call FreeMemory call _ei jmp int08new ENDP newint20 ;# Прерывание 008h ########################################################### PROC kernel ; Прерывание 008h pushf call [Dword Ptr cs:oldofs08] push di push bx push ax push es push ds push si cmp [cs:int08],0 ;¬ Если нельзя переключать задачи, je kernelend ;+ то не переключаем их. mov si,sp ;¬ mov ax,ss ;¦ ES:SI=SS:SP mov es,ax ;+ ; Инитим DS push cs pop ds ; Ищем стек задачи lea di,[ds:firsttask] ; DI = Адрес начала структуры TTASK mov al,[ds:numtask] ; AL = Номер задачи xor ah,ah ; AX = Номер задачи push dx mov dx,515 mul dx ; AX = Смещения от начала firsttask pop dx add di,ax ; DI = Абсолютное смещение вершины ; стека в структуре TTASK mov [Word Ptr ds:di+5],ss mov [Word Ptr ds:di+7],sp ; С учетом приоритетов -------------------¬ dec [Word Ptr ds:di+9] ; ¦ cmp [Word Ptr ds:di+9],0 ; ¦ jne kernelend ; ¦ mov ax,[Word Ptr ds:di+11] ; ¦ mov [Word Ptr ds:di+9],ax ;-- kernel_01: add di,515 ;¬SP=DI+515 mov sp,di ;- mov ax,ds ;¬SS=DS mov ss,ax ;- ; Сохранаяем 'остальные' регистры в структуре TTASK push si ; SP push es ; SS push cx ; CX push dx ; DX push bp ; BP ; Ещем следующую задачу int08new: xor ax,ax mov al,[ds:numtask] nexttask: inc al ;_следующую_ lea di,[ds:firsttask] cmp al,9 jne int201 xor ax,ax int201: push ax mov dx,515 mul dx add di,ax ; DI = Абсолютное смещение вершины ; стека в структуре TTASK pop ax cmp [Byte Ptr ds:di],255 je nexttask cmp [Byte Ptr ds:di],254 ; Приостановленная задача je nexttask mov [ds:numtask],al mov ax,di add ax,(515-10) mov sp,ax ; В SP имеем стек (тот что в структуре ; TTASK) следующей задачи push ds pop ss ; Востанавливаем оттуда 'остальные' регистры следующей задачи pop bp pop dx pop cx pop es pop si ; SS:SP теперь должны указывать на реальный стек задачи mov ax,es ;¬ mov ss,ax ;¦ SS:SP=ES:SI mov sp,si ;- kernelend: pop si pop ds pop es pop ax pop bx pop di push ax mov al,20h out 20h,al pop ax iret ENDP kernel ; Инициализируем дескрипторы задач ########################################### PROC inittasks mov [Byte Ptr cs:firsttask],0 mov [Byte Ptr cs:tasknum],0 mov [Byte Ptr cs:numtask],0 lea si,[tasks] mov cx,8 it1: mov [Byte Ptr cs:si],255 mov [Byte Ptr cs:si+1],254 add si,515 loop it1 ret ENDP inittasks