Данная статья в большей степени является не руководством и не мануалом, а просто моими заметками. Идея этой статьи собрать множество особенностей и знаний в одно целое, надеюсь, она кому-то пригодится =)
Что происходит с ОЗУ при загрузке компьютера
Когда вы нажимаете кнопку старта на компьютере(или замыкаете контакты на материнке) BIOS проверяет оборудование и загружает первый сектор жесткого диска(512 байт), который помечен как загрузочный, по адресу 7C00h (h — hex) и начинает выполнять программу которая лежит в этих 512 байтах. От сюда следует, что у нас в распоряжеии есть только 512 байт.
В конце нашей программы (именуемой загрузчиком) должна быть сигнатура загрузчика — это два байта 55h и AAh, по этим двум байтам BIOS определяет, является ли эта программа загрузчиком. В загрузчике мы должны написать загрузку с жесткого диска либо второго загрузчика, либо сразу ядра ОС, в нашем случае сразу ядра ОС.
Ядро ОС будет располагаться по адресу 0500h, программы по адресу 7E00h, вершина стека 7DFFh.
Структура памяти при запуске компьютера.

Ядро располагается на 3 секторе жесткого диска и будет занимать 4 сектора(4 *512) или 2 Kb.Для загрузки даных с жесткого диска будет использовать прерывание 13h и функция 42h.
У этой функции на вход идет DAPS структура, в которой описано куда, сколько и от куда грузить сектора.
Структура DAPS
-
1 байт — размер структура(в нашем случае 16 байт)
-
1 байт — всегда 0, резерв
-
1 байт — сколько загружать секторов(в нашем случае 4(размер ядра))
-
1 байт — всегда 0, резерв
-
2 байта — по какому смещению загружать данные
-
2 байта — по какому сегменту загружать данные
-
8 байт — номер сектора с которого начинать загружать данные
#define u_int16 unsigned short int #define u_char8 unsigned char #define u_long_int unsigned long int #define u_long_int64 unsigned long long int struct daps { u_char8 p_size = 16; u_char8 p_empty = 0; u_char8 p_n_setors; u_char8 p_empty2 = 0; u_int16 p_adres; u_int16 p_segment; u_long_int64 sector; file data_file; };
На file data_file пока не смотрите, это пригодиться в будущем, для удобства чтения файлов в нашей ФС (файловай системе).
Загрузчик
Код загрузчика
use16 org 7c00h cli ;запрещаем прерывания xor ax,ax ;обнуляем регистр ах mov ds,ax ;настраиваем сегмент данных на нулевой адрес mov es,ax ;настраиваем сегмент es на нулевой адрес mov ss,ax ;настраиваем сегмент стека на нулевой адрес mov sp,07DFFh ;сегмент sp указывает на текущую вершину стека sti ;разрешаем прерывания push cs pop ds mov si,paket mov ah,42h int 13h jmp 0000:0500h jmp $ paket:;DAPS db 16;const paksize db 0;null db 4;кол-во секторов db 0;null dw 0500h;смещение dw 0;сегмент dq 2;начало times(512-2-($-07C00h)) db 0 db 055h,0AAh ;16 байт 1 сегмент
Ядро ОС
Наше ядро при запуске сохраняет номер диска, который BIOS положил в регистр DL, в переменную BOOT_DISK(она нужна будет для доступа к диску, файлам и тд) и прыгает на метку START_K. То что идет после START_K ставит вектора прерываний 90h(основное API ОС) и 91h(Возврат управления ОС).
Установка векторов прерываний осуществляется с помощью этого макроса, на вход номер прерывания и адрес функции обработчика.
macro SET_INTERRUPT_HANDLER NUM, HANDLER { pusha xor ax,ax push ax pop es mov al,NUM mov bl,4h mul bl mov bx,ax mov si,HANDLER mov [es:bx],si add bx,2 push cs pop ax mov [es:bx], ax popa }
Далее загружается таблица файлов, в нашей ОС она находится во втором секторе жесткого диска. Загрузка также происходит через DAPS.
DAPS таблицы файлов
DAPS_TABEL_FILES: db 16;const paksize db 0;null db 1;кол-во секторов db 0;null dw TABLE_FILES;смещение dw 0;сегмент dq 1;начало
Загрузка с помощью макроса и функции 17h прерывания 90h(которое установило ядро)
macro LOAD_DAPS DAPS { push cs pop ds mov si, DAPS mov ah, 17h int 90h }
Функция 17h прерывания 90h(по сути просто бертка над 13h)
cmp ah,17h;-|-in - ds:si - daps je HF_LOAD_DAPS iret HF_LOAD_DAPS: call F_LOAD_DAPS iret ;-|-in - ds:si - daps ; |-out - (load file table on ram) F_LOAD_DAPS: mov dl,[BOOT_DISK];вот и пригодилась наша переменная с номером диска mov ah,42h int 13h ret
Далее идет печать строки приветствия с помощью макроса PRINT.
macro PRINT STR,COLOR { mov ah,2 push cs pop ds mov di,STR mov bl,COLOR int 90h }
Он вызывает 2 функцию прерывания 90h, которая вызывает функцию F_PRINT.
;--------------------Печать Форматированной Строки------------------------- F_PRINTSF:;ds:di-str,bl-color call F_GET_CURSOR xor cx,cx mov cl,[ds:di] inc di MAIN_START_F_PRINTSF: call F_READ_VIDEO mov ah,013h push ds pop es mov bp,di mov al,1 int 10h ret ;--------------------Печать Строки------------------------- F_PRINT:;ds:di-str,bl-color push di push ds call F_GET_CURSOR call F_GET_LEN_STR pop ds pop di call MAIN_START_F_PRINTSF ret ;-------------------Чтение видео режима------------------------------------------------------ F_READ_VIDEO:;out al=video ah=число колонок bh= номер активной страницы дисплея mov ah,0fh int 10h ret ;------------Получение курсора; Выход: dh,dl - string,char ch,cl=нач.и кончеч строки курсора ---------------------------------------------------- F_GET_CURSOR:;out= dh,dl - string,char ch,cl=нач.и кончеч строки курсора call F_READ_VIDEO mov ah,03h int 10h ret ;-------------------Фуекция подсчета длины строки.------------------------------------------------------------------------------ ;-|-in - ds:di=str, cx=len ; |-out - cx=len F_GET_LEN_STR: xor cx,cx START_F_GET_LEN_STR: mov al,[ds:di] cmp al,0 je EXIT_F_GET_LET_STR inc di inc cx jmp START_F_GET_LEN_STR EXIT_F_GET_LET_STR: ret
Далее идет поиск файла с именем cmd и его запуск. Реализованно это с помощью макросов SEACH_FILE и LOAD_DAPS.
macro SEACH_FILE TABLE_FILES, FILENAME { push cs pop ds mov bx,TABLE_FILES mov di, FILENAME mov ah,10h int 90h }
Макрос вызывает 10h функцию прерывания 90h.
;-------------------Поиск адреса файла------------------------------------------------------------------------------------------ ;-|-in - ds:bx=tableFiles, ds:di=flename ; |-out - ch-dorogka cl=sector, al=numSectors ah = type ; |-except - not found - ax=0, cx=0 F_SEACH_FILE: jmp startpfseachFile pfseachFilecxsave: db 0 pfseachFilebxsave: db 0,0 pfseachFiledisave: db 0,0 startpfseachFile: xor cx,cx mov cl,32 add bx,4 mov [pfseachFiledisave],di startSeach: mov [pfseachFilecxsave],cl mov [pfseachFilebxsave],bx mov di,[pfseachFiledisave] mov si,[pfseachFilebxsave] call F_CMP_STRING cmp al,0 je pgetDataForstartFile mov cl,[pfseachFilecxsave] mov bx,[pfseachFilebxsave] add bx,16 loop startSeach xor bx,bx xor cx,cx xor ax,ax jmp exitpfseachFile pgetDataForstartFile: mov bx,[pfseachFilebxsave] mov di,bx dec di mov cl,[ds:di] dec di mov ch,[ds:di] mov al,ch dec di mov ch,[ds:di] dec di mov ah,[ds:di] exitpfseachFile: ret
Запуск файла cmd.
START_PROGRAMM: mov si, DAPS_RUNTIME_FILE mov [si + 2], al mov [si + 8], cl LOAD_DAPS DAPS_RUNTIME_FILE ;LOAD_FILE ch, cl, al, 0000, 0500h NEW_LINE jmp 0000:7E00h
DAPS программ.
DAPS_RUNTIME_FILE: db 16;const paksize db 0;null db 1;кол-во секторов db 0;null dw 7E00h;смещение dw 0;сегмент dq 7;начало
Код Ядра
org 0500h GLOBAL: mov [BOOT_DISK],dl jmp START_K ;----------------------------------------------------------- include 'INCLUDES\MACROS.INC' include 'INCLUDES\BASE_FUNCTIONS.INC' include 'INCLUDES\INTERRUPT_HANDLER_RETURN.INC' include 'INCLUDES\MAIN_INTERRUPT_HANDLER.INC' include 'INCLUDES\KEYBOARD.INC' include 'INCLUDES\CONST.INC' ;----------------------------------------------------------- START_K: SET_INTERRUPT_HANDLER 90H,MAIN_INTERRUPT_HANDLER SET_INTERRUPT_HANDLER 91H,INTERRUPT_HANDLER_RETURN LOAD_DAPS DAPS_TABEL_FILES PRINT HELLO_WORLD, BLACK MAIN: ;NEW_LINE ;PRINT INPUT_STR, BLACK ;GET_STRING BUFFER, 13 SEACH_FILE TABLE_FILES, CMD cmp ax,0 je PRINT_ERROR cmp ah,1 je START_PROGRAMM jmp MAIN START_PROGRAMM: mov si, DAPS_RUNTIME_FILE mov [si + 2], al mov [si + 8], cl LOAD_DAPS DAPS_RUNTIME_FILE ;LOAD_FILE ch, cl, al, 0000, 0500h NEW_LINE jmp 0000:7E00h PRINT_ERROR: NEW_LINE PRINT ERROR, RED jmp MAIN RETURN_INT: jmp MAIN ;сюда передает управление int 91h jmp $ DAPS_RUNTIME_FILE: db 16;const paksize db 0;null db 1;кол-во секторов db 0;null dw 7E00h;смещение dw 0;сегмент dq 7;начало DAPS_TABEL_FILES: db 16;const paksize db 0;null db 1;кол-во секторов db 0;null dw TABLE_FILES;смещение dw 0;сегмент dq 1;начало HELLO_WORLD: string "WaaOS Loaded, Hello! =)" ERROR: string "Command not found :(" CMD: string "cmd" INPUT_STR: string "user:>" BOOT_DISK: db 0 BUFFER: db 13 dup(0) TMP: db 255 dup(0) TABLE_FILES: CALC_SIZE SIZE_KERNEL, GLOBAL
Код CMD
#include "BASE_LIB.H" void clear_str_file_name(u_char8 *str, u_char8 len){ for(u_int16 i = 0; i < len; i++){ str[i] = 0; } } void main(void) { u_char8 user[] = "user:>"; u_char8 not_found[] = "Command not found :("; while (true) { print(new_line, Black); print(user, White); f_string user_guffer = input(); for(u_char8 i =0 ; i < 254; i++){ if(user_guffer.data[i] == ' '){ user_guffer.data[i] = 0; } } u_char8 file_name[13]; clear_str_file_name(file_name, 13); for(u_char8 i = 0; i < 13; i++){ if(user_guffer.data[i] == 0) break; if(user_guffer.data[i] == ' ') break; file_name[i] = user_guffer.data[i]; } if(file_name[0] != ' ' && file_name[0] != 0){ daps daps_file = get_r_daps_file(file_name, (u_int16) 0x07E00); print(new_line, Black); if(daps_file.p_empty != 1){ start_programm(&daps_file, user_guffer.data); } else { print(not_found, Red); } } } }
Заключение
Если вам интересно будет почитать про файловую систему, которая используется в этйо ОС, и библиотеку для СИ и доп. функции прерывания 90h, сделю вторую, третью и тд части. Спасибо что дочитали до конца.
Авторы: @lllzebralll @aovzerk
ссылка на оригинал статьи https://habr.com/ru/post/668926/
Добавить комментарий