Создание мини-ОС

19.09.2011

В статьях Создание образа диска и Создание загрузочного диска было рассмотрено создание загрузочного сектора и создание образа диска операционной системы. Попробуем создать теперь более сложную конструкцию

Наша операционная система будет состоять из трех файлов. которые займут три сектора по 512 байт, и еще один сектор в 512 байт будет использоваться для хранения данных.

Что будет представлять операционная система? Первый файл само собой будет загрузчик, который будет загружать второй файл - ядро. Хотя, конечно, ядром его назвать нельзя, поскольку в данном случае это будет всего лишь оболочка наподобие Shell, куда будут вводиться команды на выполнение тех или иных приложений. И также у нас будет одно приложение - мини текстовый редактор. В нем мы сможем набирать, редактировать и сохранять данные в четвертом секторе диска.

В качестве инструмента программирования выберем FASM по причине большей компактности программ. Тем более FASM поддерживает прямые переходы jmp 0000:0500h. В MASM для этого нам пришлось создавать бы переменную, которая содержала бы адрес. Это бы вело к увеличению размера программы, который итак ограничен 512 байтами.

Немного видоизменим загрузочный сектор, убрав из него все лишнее. Это будет файл fboot.asm.

;===================== Загрузочный сектор. Евгений Попов, 2011===================== 
;==================================================================================
 org 7c00h 	;BIOS производит чтение 512 байт первого сектора MBR в ОЗУ по адресу 0x00007C00 
			;(0x07C0:0x0000 в формате реального режима), затем прочитанному коду передаётся управление
start:
		cli 			;запрещаем прерывания
        xor ax,ax		;обнуляем регистр ах
        mov ds,ax		;настраиваем сегмент данных на нулевой адрес
        mov es,ax		;настраиваем сегмент es на нулевой адрес
        mov ss,ax		;настраиваем сегмент стека на нулевой адрес
        mov sp,07C00h	;сегмент sp указывает на текущую вершину стека
        sti		    ;разрешаем прерывания
           
        mov ax, 0002h  	;очищаем экран - функция 00h прерывания 10h	
        int 10h
        
        mov dx,0h
        call SetCursorPos
        
        mov bp, msg             
        mov cx, 13
        call PrintMes	;Вывод на экран строки msg
        
        add dh,1		;переходим на одну строку ниже
        call SetCursorPos
        mov bp, Con             ;Вывод на экран строки Con
        mov cx, 23
        call PrintMes
                
		 mov ah,10h
         int 16h
                
Continue:
        cmp al, 0Dh 	;Если нажимаем на Enter, то переходим к загрузке ядра
        jz Kernel
        jmp Continue	;Если нет, снова ожидаем нажатия клавиши
                
Kernel:
  		mov ax,0000h
        mov es,ax
        mov bx,500h
        mov ch,0			;номер цилиндра - 0
        mov cl,02h			;начальный сектор - 2
        mov dh,0			;номер головки - 0
        mov	dl,80h			;жесткий диск - 80h
        mov al,01h			;кол-во читаемых секторов -1
        mov ah,02h
        int 13h
        jmp 0000:0500h		;переход на 0000:0500h, куда загружен второй сектор

;===================== Подпрограммы ===================================
PrintMes:                   ;в регистре  bp - строка, в регистре cx - длина этой строки
        mov bl,04h			;в регистре  bl- атрибут
        mov ax,1301h		 функция 13h прерывания 10h
        int 10h
        ret
        ;----------------------------------
SetCursorPos:        ;установка курсора : функция 02h прерывания 10h
        mov ah,2h
        xor bh,bh
        int 10h 
        ret
           
;===================== выводимые сообщения===================== 
      	msg db 'OS Loading...',0     
        Con db 'Press Enter to Continue',0
 
times(512-2-($-07C00h)) db 0
db 055h,0AAh ;сигнатура, символизирующая о завершении загрузочного сектора
 

Теперь файл ядра - fkernel.asm. Оболочка будет выводить приглашение к вводу программы. Мы же должны напечатать команду write и после нажатия клавиши Enter перейти в текстовый редактор

org 500h				;этот сектор будет загружаться по адресу 0000:0500h
message:
	mov ax, 0002h  	;очищаем экран
        int 10h
        
	mov dx,0h
	call SetCursorPos
        mov bp, msg
        mov cx, 20
        mov bl,04h					
        xor bh,bh
        mov ax,1301h
        int 10h			;вывод приглашения к вводу команды
        
        add dh,2			;переводим курсор на один пункт вниз для ввода команды
        call SetCursorPos
        mov si,0
		
Command: 
	mov ah,10h
        int 16h
        cmp ah, 0Eh		;Если нажата клавиша BackSpase - удалить символ
        jz Delete_symbol
        cmp al, 0Dh
        jz Input_Command
        mov [string+si],al
        inc si
        mov ah,09h
        mov bx,0004h
        mov cx,1
        int 10h
        add dl,1
	call SetCursorPos
 	jmp Command
        
Input_Command:		;Если нажат Enter, то переходим в третий сектор
	mov ax,cs
	mov ds,ax
	mov es,ax
	mov di,string
	push si		;так как содержание регистра si меняется, сохраним в стеке
	mov si,write
	mov cx,5
	rep cmpsb ;сравниваем строки - если команда write, то переходим
	je wrt
	pop si
	jmp Command
		
Delete_symbol:
	cmp dl,0
	jz Command
	sub dl,1		;сдвигаем курсор влево
	call SetCursorPos
	mov al,20h		;вместо уже напечатанного символа выводим пробел
	mov [string + si],al ;стираем символ в строке
	mov ah,09h
	mov bx,0004h
        mov cx,1
        int 10h
        dec si			;уменьшаем кол-во напечатанных символов
	jmp Command
		
wrt:	mov ax,0000h
        mov es,ax
        mov bx,700h         
        mov ch,0			;номер цилиндра - 0
        mov cl,03h			;начальный сектор - 3
        mov dh,0			;номер головки - 0
        mov dl,80h			;жесткий диск - 80h
        mov al,01h			;кол-во читаемых секторов -1
        mov ah,02h
        int 13h
	jmp 0000:0700h

SetCursorPos:        ;установка курсора
        mov ah,2h
        xor bh,bh
        int 10h 
        ret

msg db 'Input the command...',0
write db 'write',0
string db 5 dup(?) ;буфер для ввода команды

Последняя часть - создание текстового редактора (файл fwriter.asm). Поскольку создание текстовых редакторов на ассемблере - не самое легкое дело, его функционал будет минимальным. Редактор позволит сохранять текст, редактировать, загружать сохраненный текст. Основной недостаток - макисмальное количество символов текста - 256. Что конечно не очень хорошо, поскольку в этом случае при сохранении текста у нас заполняется всего половина четвертого сектора.

org 700h
start:
  	mov ax,0002h	;очищаем экран
  	int 10h
        xor dx,dx
        call SetCursorPos	;устанавливаем курсор
                                
        mov bp, msg
        mov cx, 24
        call PrintMes	;Вывод на экран строки msg
        
        mov dl,0
        mov dh,1
        call SetCursorPos	;переводим курсор на одну строку вниз
        mov bp, helper
        mov cx,77
        call PrintMes		;Вывод на экран строки helper
        
Option:						;Выбор - загрузить текст из четвертого сектора или начать новый
        mov ah,10h
        int 16h
        cmp ah, 3Bh			;Если нажата клавиша F1 - загружаем текст
        jz Load_text
        cmp al, 0Dh			;Если нажата клавиша Enter - печатаем текст
        jz Print_text
	jmp Option
        
Load_text:					;Загрузка текста
	mov ax,0000h
        mov es,ax
        mov bx,string         
        mov ch,0			;номер цилиндра - 0
        mov cl,4			;начальный сектор - 4
        mov dh,0			;номер головки - 0
        mov dl,80h			;жесткий диск - 80h
        mov al,01h			;кол-во читаемых секторов -1
        mov ah,02h
        int 13h
        xor dl,dl
        mov dh,3
        call SetCursorPos
        mov bp, string
        mov cx, 256
        call PrintMes
        mov si,255
        add dl, 15			;256-80*3=16
        add dh,3
        call SetCursorPos
        jmp Command
        
Print_text:
        xor dx,dx
        add dh,3
        call SetCursorPos	;получаем позицию курсора
        mov si,0			;Печать символов
Command: 
	mov ah,10h
        int 16h
        cmp al, 1Bh		;Если нажата клавиша Esc - выход из приложения
        jz Esc
        cmp al, 0Dh		;Если нажата клавиша Enter - переход на новую строку
        jz Caret
        cmp ah, 0Eh		;Если нажата клавиша BackSpase - удалить символ
        jz Delete_symbol
        cmp ah, 3Ch		;Если нажата клавиша F2- сохранить текст
        jz Save_text
        cmp si, 256
        jz Command
        mov [string + si],al
        inc si
        mov ah,09h
        mov bx,0004h
        mov cx,1
        int 10h
        add dl,1
        call SetCursorPos
 	jmp Command
		
Caret:	;переход на новую строку
	add dh,1
	xor dl,dl
        call SetCursorPos
        jmp Command
        
Save_text:	;запись текста в 4 сектор
	mov ax,0000h
        mov es,ax
	mov ah, 03h
	mov al,1
	mov ch,0
	mov cl,4
	mov dh,0
	mov dl,80h
	mov bx, string
	int 13h
	jmp Command
		
Delete_symbol: ;удаление символа после нажатия BackSpase
	cmp dl,0
	jne Delete
	cmp dh,3
	jz Command
	sub dh,1
	mov dl,79
	jmp Cursor_Pos
Delete:		sub dl,1			;сдвигаем курсор влево
Cursor_Pos: 
	call SetCursorPos
	mov al,20h			;вместо уже напечатанного символа выводим пробел
	mov [string + si],al ;стираем символ в строке
	mov ah,09h
        mov bx,0004h
        mov cx,1
        int 10h
        cmp si,0
        jz Command
        dec si				;уменьшаем кол-во напечатанных символов
	jmp Command
Esc:     
        jmp 0000:0500h		;возвращаемся во второй сектор
        
;===================== Подпрограммы ===================================
  PrintMes:                ;в регистре  bp - строка, в регистре cx - длина этой строки
        mov bl,04h			;в регистре  bl- атрибут
        mov ax,1301h
        int 10h
        ret
        ;----------------------------------
  SetCursorPos:        								;установка курсора
        mov ah,2h
        xor bh,bh
        int 10h 
        ret
            
        ;===================== выводимые сообщения===================== 
      	msg db 'This is a text writer...',0 
      	helper db 'To print text - press Enter, to load text - press F1, to save text - press F2',0
        string db 256 dup(?)	;буфер для вводимого сообщения

Теперь скомпилируем три файла и создадим из них образ

macro align value { db value-1 - ($ + value-1) mod (value) dup 0 }
HEADS = 1
SPT = 4	;4 сектора по 512 байт
Begin:
	file "fboot.bin",512 ; загрузчик
	file "fkernel.bin" ; первый файл, типа оболочка shell
	align 512
	file "fwriter.bin" ; второй файл - текстовый редатор
	align 512
	align HEADS*SPT*512

Загружаем систему через Bochs


Нажимаем Enter и загружаем ядро


Вводим команду write и переходим в текстовый редактор

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850