16-bit operating system on your knees
Preface
Hello. This is my first article and it will be about developing your own operating system. If you notice any errors while reading or you have deeper knowledge in this area, write comments and I will make corrections. The author is still learning this difficult craft. The full OS source code will be provided at the end of the article. The OS is written entirely in NASMfor Intel x86-64 processor architecture.
In the beginning there was a word…
For a more complete understanding of the process of starting a computer, I advise you to read the article.
After clicking the “Power“, the system controller located on the motherboard sends a signal to turn on the processor. The processor then loads and executes the code BIOS.
The BIOS code contains an algorithm for checking components, this check is called POST. After checking, the process of reading the first 512 bytes (1 sector) from the hard drive specified in the BIOS settings in the tab Boot -> Boot Device Priority (May vary depending on BIOS version). The processor, let’s say, “looks” for the boot sector, it is known to us as MBR.
And the word was 0xaa55
As I put it above, the processor is “searching” for the boot sector. There must be a magic number at the end of the sector 0xaa55. Thanks to this magic number, the processor “understands” that this is a boot sector, then loads it into RAM at the address 0x7c00 and executes it in real mode. If the hard disk does not contain a boot sector, interrupt 0x19 is called and the processor moves to the next disk. If there are no more devices, it will display an error like “No bootable devices found.“.
Registers
In real processor operation mode”Real Mode“, 16-bit registers are available to the user: ax, bx, cx, dx, sp, si, di, bp. Also, the user has access to 8-bit registers. 8-bit registers form a 16-bit register.
High 8-bit register | Low 8-bit register | 16-bit register |
A.H. | AL | AX |
B.H. | B.L. | BX |
CH | C.L. | CX |
D.H. | D.L. | DX |
Interrupts
BIOS provides developers with a whole set of tools for working with peripherals, graphics, hard drives, and so on. The BIOS provides 256 interrupts. I will provide a table of interrupts used in the process of writing an OS.
Interrupt number | Interrupt assignment |
0x13 | Working with a hard drive |
0x10 | Video service. Needed to display text on the screen |
0x16 | Using the keyboard |
0x15 | Working with memory. Needed to delay code execution |
0x19 | Reboot the system using “warm” reboot without clearing memory or restoring the interrupt vector table (IVT) |
x86-64 processor operating modes
x86-64 processors can operate in 3 main modes. This is real (real mode), protected (protected mode) and 64-bit mode (long mode). Please note that starting from Protected Mode, BIOS interrupt support is no longer supported. To work with individual computer components, you need to write drivers.
Real mode – This is the mode the processor enters after turning on or rebooting. This is a standard 16-bit mode in which only 1MB of physical memory is available, and the processor's capabilities are almost not used, and if used, then to a small extent.
Protected mode or legacy mode – This is a 32-bit mode, considered the main one. In protected mode, the operating system can get the most out of the processor. This mode gives access to 4GB of physical memory. And when you enable a special address translation mechanism, you can access 64GB of physical memory. You can only switch to protected mode from real mode. This mode is called protected because it allows you to protect operating system data from applications. “Native” data size for this mode DWORD.
Long mode – 64-bit mode. In this mode you can access 2⁵² bytes of physical memory and 2⁴⁸ bytes of virtual memory. You can switch to 64-bit mode only from protected mode. In this “Native” mode for the processor, the data size is DWORDbut you can also operate QWORD.
In addition to the 3 above modes, 2 sub-modes are supported
8086 virtual processor mode – This is a submode of protected mode to support 16-bit applications. It can be enabled for a single task in a multitasking 32-bit operating system.
Compatibility mode for long mode – In compatibility mode, applications have access to 4GB of memory and full support for 32 and 16-bit code. Compatibility mode can be enabled for a single task in a multitasking 64-bit operating system. In compatibility mode, the address size is 32-bit, but the operand size cannot be QWORD.
In addition to the above modes, there is System Control Mode (System Management Mode), which the processor enters when receiving a special interrupt SMI. System management mode is designed to perform certain actions with the ability to completely isolate them from application software and even the operating system. System management mode can be used to implement computer energy management system or security and access control functions.
Let's move on to practice
Loader – This is the executable code that loads the operating system. The bootloader size should not exceed 512 bytes. This size is not enough to fit the entire operating system; to do this, we will place the bootloader code in the boot sector, and the operating system outside it. For this we need interrupt 0x13.
org 0x7c00
jmp pre_boot
pre_boot:
cli ; Запрещаем прерывания
xor ax, ax ; Зануляем регистры
mov ds, ax ; Зануляем регистры
mov es, ax ; Зануляем регистры
mov ss, ax ; Зануляем регистры
mov sp, 0x7c00
; Чтение и размещение операционной системы в ОЗУ
mov ah, 0x02; Функция 0x02 - Работа с жёстким диском
mov al, 7 ; Количество секторов на чтение. В нашем случае 7 = 7*512 = 3584 байт
mov ch, 0x00 ; Номер цилиндра
mov cl, 0x02 ; Номер начального сектора 2. 1 сектор - загрузчик, 2 сектор - ОС.
mov dh, 0x00 ; Сторона диска
mov dl, 0x80 ; Номер устройства. Начинается с 0x80 - 0, 0x81 - 1, ...
mov bx, 0x7e00 ; Адрес загрузки данных
int 0x13 ; Прерывание чтения сектора
jc read_error ; Если возникает ошибка, переходим к выполнению куска кода read_error.
jmp 0x7e00 ; Если ошибок не возникло, то переходим к загруженному коду. 0x7c00 + 512 = 0x7e00
read_error:
mov ah, 0x0e ; Номер функции в прерывании 0x10, вывод символа на экран.
mov al, 'R' ; Загружаем символ
int 0x10 ; Выводим символ
mov al, 'E'
int 0x10
mov al, 'A'
int 0x10
mov al, 'D'
int 0x10
mov al, ' '
int 0x10
mov al, 'E'
int 0x10
mov al, 'R'
int 0x10
mov al, 'R'
int 0x10
mov al, 'O'
int 0x10
mov al, 'R'
int 0x10
mov al, '!'
int 0x10
jmp $ ; Бесконечный переход к этой метке. Зависаем на месте с выводом ошибки.
times 510 - ($- $$) db 0 ; Заполняем оставшуюся часть кода нулями.
dw 0xaa55 ; Магическое число в конце сектора.
Important note!
The operating system will be located in one file and its actual size at the moment is 7 sectors. If the actual file size is less than the specified sectors for reading, the error “READ ERROR!“When writing an OS, keep this in mind!
Now that the bootloader is ready, let's start writing the I/O library. I will place these functions in another file, in the “drivers” directory.
For convenience, I added comments in the language style C, to quickly determine which registers and which values need to be placed to call a specific function. Now let's go through the functionality:
cls – Screen cleaning.
out_char – Displaying the symbol on the screen.
out_string – Output a line to the screen.
in_char – User character input.
in_string – User input string.
compare_str – Comparison of two strings.
clear_buffer – Clear the buffer (Zero).
new_line – Move the input carriage to a new line.
; ============================================================================
; Библиотека для ввода/вывода текстовой информации, с помощью прерываний BIOS
; ============================================================================
global cls ; void cls();
global out_char ; void out_char(char bl);
global out_string ; void out_string(char* si);
global in_char ; char in_char() return char al;
global in_string ; void in_string(char[]* si);
global comapre_strs ; int (const char* first_word[] si, const char* last_word[] bx) return cx (1 - равны, 0 - не равны);
global clear_buffer ; void (const char* buf_address[] si, int buf_size bx);
global new_line ; void new_line();
section .text
new_line: ; Перевод каретки на новую строку
push ax ; Сохраняем значение регистра ax в стеке
mov ah, 0x0e ; Номер функции прерывания 0x10. Вывод
mov al, 0x0a ; Символ перевода каретки в начало
int 0x10 ; Вызов прерывания для работы с видеосервисом
mov al, 0x0d ; Символ перевода строки
int 0x10
pop ax ; Восстанавливаем значение в регистре ax
ret ; Выходим из функции
cls:
push ax ; Сохраняем значение ax
mov ah, 0x00 ; Номер функции прерывания 0x10. Изменение видеорежима
mov al, 0x03 ; Номер видеорежима. 0x03 - текстовый видеорежим.
int 0x10
pop ax ; Восстанавливаем значение регистра ax
ret ; Выходим из функции
out_char: ; Вывод символа на экран
push ax
mov ah, 0x0e
mov al, bl ; В регистр bl мы заранее положили символ на вывод
int 0x10
pop ax
ret
out_string: ; Вывод строки на экран
push ax
mov ah, 0x0e
call __out_string_next_char
pop ax
ret
__out_string_next_char:
mov al, [si] ; В регистре si храниться адрес начала строки. Помещаем значение из адреса si в al
cmp al, 0 ; Затем сравниваем al с 0
jz __out_string_if_zero ; если al = 0 значит строка закончилась
int 0x10 ; если al != 0 значит, по этому адресу что-то есть, выводим символ на экран
inc si ; Увеличиваем si на 1
jmp __out_string_next_char ; Выполняем функцию снова
__out_string_if_zero:
ret ; Покидаем функцию
in_char: ; Пользовательский ввод символа
push bx
mov ah, 0
int 0x16 ; Символ сохранён в регистр al
mov ah, 0x0e
mov bh, 0
mov bl, 0x07
int 0x10 ; Вывод введённого символа на экран
pop bx
ret
comapre_strs: ; Сравнивание строк
push si
push bx
push ax
__comapre_strs_comp:
mov ah, [bx]
cmp [si], ah
jne __comapre_strs_first_zero
inc si
inc bx
jmp __comapre_strs_comp
__comapre_strs_first_zero:
cmp byte [bx], 0
jne __comapre_strs_not_equal
mov cx, 1
pop si
pop bx
pop ax
ret
__comapre_strs_not_equal:
mov cx, 0
pop si
pop bx
pop ax
ret
clear_buffer:
; si - Адрес буфера
; bx - Количество байт на очистку
push cx
mov cx, 0
__clear_buffer_loop:
cmp cx, bx
je __clear_buffer_end_loop
mov byte [si], 0
inc si
inc cx
jmp __clear_buffer_loop
__clear_buffer_end_loop:
pop cx
ret
in_string: ; Пользовательский ввод строки. Адрес буфера хранится в si
push ax
push cx
xor cx, cx
__input_string_loop:
mov ah, 0
int 0x16
cmp al, 0x0d ; Если пользователь нажал Enter, то обрабатываем это событие
je __input_string_enter
cmp al, 0x08 ; Если пользователь нажал Backspace, то обрабатываем это событие
je __input_string_backspace
mov [si], al
inc si
inc cx
mov ah, 0x0e
mov bh, 0
mov bl, 0x07
int 0x10
cmp cx, 255 ; Если Пользователь ввёл 255 символов
je __input_string_enter ; То прыгаем в событие нажатия на Enter
jmp __input_string_loop
__input_string_enter:
mov ah, 0x0e ; Номер функции int 0x10 - вывод символа
mov al, 0x0d ; Перевод каретки на новую строку
mov bh, 0
mov bl, 0x07 ; Цвет выводимого символа 0 - чёрный фон 7 - белый символ
int 0x10
mov al, 0xa ; Перевод каретки в начало строки
int 0x10
mov byte [si], 0 ; Помещаем в конец строки 0
pop cx
pop ax
ret
__input_string_backspace:
cmp cx, 0 ; Проверка номера символа по счёту. Если это 0 символ - значит нужно запретить стирание символа, потому что, пользователь может случайно стереть выводимую ОС информацию.
je __input_string_loop ; Если это 0 символ, то возвращаемся в цикл ввода
mov ah, 0x0e ; Иначе, эмулируем нажатия на Backspace, Пробел, Backspace
mov al, 0x08 ; Backspace
int 0x10
mov al, 0x20 ; Пробел
int 0x10
mov al, 0x08 ; Backspace
int 0x10
mov byte [si], 0
dec si ; Уменьшаем si на 1. si - адрес cx - номер введённого символа. Уменьшаем два этих регистра на один
dec cx
jmp __input_string_loop ; Возвращаемся в цикл ввода
Pay attention to the lines 157-163. On line 157 in the comment I stated, “emulate pressing Backspace, Space, Backspace“. When the user presses Backspace while typing, the caret moves to the left by 1 character and remains under the previous character. The user cannot erase it, can only replace it with another character (Reminiscent of the enabled mode Insert on keyboard). This can be bypassed through a set of actions, Backspace, Space, Backspace. To change this behavior, these actions are pre-written in the code.
operating system
The operating system must support at least the command line and command set. We implement work with commands in a similar way to Callback functions.
User enters a command -> Command processor compares user input with existing commands. If the command name and user input are equal, then the command execution begins, otherwise we check the next command. If the command is not found, we display the error “Comand not found!”.
jmp boot
boot:
call cls ; Очищаем экран
call IBM_WELCOME_WINDOW ; Вызываем функцию вывода логотипа IBM
call cls ; Очищаем экран
mov si, welcome
call out_string ; Выводим приветственное сообщение
jmp input_loop ; Переходим к выполнению цикла пользовательского ввода
IBM_WELCOME_WINDOW:
mov si, IBM_WELCOME
call out_string
mov ax, 0x8600 ; Время ожидания, в мс
mov cx, 30 ; Номер функции 30 - ожидание
int 0x15 ; Вызываем 0x15 прерывание для ожидания
ret
input_loop:
mov si, buffer
mov bx, 255
call clear_buffer ; Очищаем буфер от пользовательского ввода
mov si, prompt
call out_string ; Выводим live@cd>
mov si, buffer
call in_string ; Даём пользователю возможность ввода команды
jmp OS_callback ; Проверяем что ввёл пользователь
jmp input_loop ; Повторяем цикл
OS_callback:
mov si, help_in
mov bx, buffer
call comapre_strs ; Проверяем пользовательский ввод с help
cmp cx, 1
je Callback_HELP ; Если пользователь ввёл help, то прыгаем в Callback_HELP
mov si, cls_in ; Проверяем пользовательский ввод с cls
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_CLS ; Если пользователь ввёл cls, то прыгаем в Callback_CLS
mov si, info_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_INFO
mov si, reboot_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_REBOOT
mov si, echo_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_ECHO
jne Callback_WRONG ; Если ни одна команда не подошла, то сообщаем, что команда введена неправильно
jmp input_loop
Callback_HELP:
mov si, help_out
call out_string ; Выводим справку по командам
jmp input_loop
Callback_CLS:
call cls ; Вызываем функцию очистки экрана
jmp input_loop
Callback_WRONG: ; Неверная команда
mov si, wrong_command_1
call out_string ; Выводим первую часть сообщения: Command '
mov si, buffer ;
call out_string ; Выводим то, что ввёл пользователь
mov si, wrong_command_2 ;
call out_string ; Выводим выводим вторую часть сообщения: ' not found. Type 'help' to get all commands
jmp input_loop ; Переходим в цикл пользовательского ввода
Callback_INFO:
mov si, info_out
call out_string ; Тот же алгоритм, что и help
jmp input_loop
Callback_REBOOT:
mov ah, 0 ; Номер функции 0 - "тёплая" перезагрузка
int 0x19 ; Выполняем 0x19 прерывание
jmp $ ; Зависаем. Можно не добавлять, на всякий случай добавил
Callback_ECHO:
mov si, echo_out
call out_string ; Выводим просьбу ввести слово, которое затем выведем
mov si, buffer
call in_string ; Ожидаем пользовательский ввод
mov si, buffer
call out_string ; Выводим введённое слово
call new_line ; Переходим на новую строку
jmp input_loop ; Возвращаемся в цикл ввода
%include "drivers/IO.asm" ; Подключаем библиотеку IO.asm
; Далее секция данных. тут думаю проблем с пониманием не возникнет.
welcome db "Welcome to TermOS!", 0x0a, 0x0d, "Type 'help' to get command list!", 0x0a, 0x0d, 0
prompt db "live@cd:>", 0
wrong_command_1 db "Command: '", 0
wrong_command_2 db "' not found. Type 'help' to get all commands", 0x0a, 0x0d, 0
echo_out db "Echo: ", 0
help_in db "help", 0
cls_in db "cls", 0
info_in db "info", 0
reboot_in db "reboot", 0
echo_in db "echo", 0
info_out db "TermOS x16 (Terminal Operation System 16-bit) v.0.0:", 0x0a, 0x0d, " This is operation system in development.", 0x0a, 0x0d, " Author: Daniil Kulikovskiy.", 0x0a, 0x0d, " Made in Russia!", 0x0a, 0x0d, 0
help_out db " cls - Clear screen", 0x0a, 0x0d, " info - Get system info", 0x0a, 0x0d, " reboot - Reboot computer", 0x0a, 0x0d, " echo - Write text in screen", 0x0a, 0x0d, 0
IBM_WELCOME db " ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ======== ======== ====== ======= ", 0x0a, 0x0d," ======== ========= ======== ======== ", 0x0a, 0x0d," === == === ======= ======= ", 0x0a, 0x0d," === ====== ======== ======== ", 0x0a, 0x0d," === ====== == ===== ===== == ", 0x0a, 0x0d," === == === == ========= == ", 0x0a, 0x0d," ======== ========= ===== ======= ===== ", 0x0a, 0x0d," ======== ======== ===== = ===== ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," (C) COPYRIGHT 1981, 1996 IBM CORPARATION - ALL RIGHTS RESERVED ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d, 0
buffer times 255 db 0
Please notice!
jmp – unconditional jump to a label or address.
call – unconditional jump to a label or address, saving the return address on the stack. After completing the work of a function that is called via call, you should always write ret.
ret – go to the address specified in the stack.
Why is 0x0a, 0x0d, 0 indicated at the end of the data label??
0x0a – Move the carriage to the beginning of the line.
0x0d – Line translation.
0 – A zero is added to the line to indicate the end of the line.
Using the command “help“, let's look at the principle of operation of all commands. There are 2 labels in the code help_in And help_out. help_in – the name of the command, user input will be compared with it. help_out – Information displayed on the screen.
The first thing that happens in the code is a transition to the label input_loop, where the buffer is cleared and the user is expected to enter a command. The command entered by the user is saved in the buffer, then the transition to the label occurs OS_callback – In this function, the entered command is checked, and if the command converges in one of the checks, the execution of this command begins, otherwise an error is output and a return to the input loop.
To add your own command, you need to write its logic in a separate callback function, then write the name of the command and add the code for processing your command in OS_callback. It is important, after executing your command, to always return to the mark input_loop for correct operation of the OS.
OS_callback:
mov si, you_command_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_YOU_COMMAND
...
Callback_YOU_COMMAND:
...
jmp input_loop
you_command_in db "you command",0
I remind you! If you add functionality, do not forget to check the file size. It may turn out that you add functionality, but at launch it will not be implemented or not fully implemented. Check the number of sectors to read and the file size!
Assembly and first launch
The operating system must be compiled using NASM in “BIN“ format. You must have NASM and qemu installed in advance.
nasm -f bin TermOS.asm -o TermOS.bin
qemu-system-x86_64 TermOS.bin
Source
drivers/IO.asm
; ============================================================================
; Библиотека для ввода/вывода текстовой информации, с помощью прерываний BIOS
; ============================================================================
global cls ; void cls();
global out_char ; void out_char(char bl);
global out_string ; void out_string(char* si);
global in_char ; char in_char() return char ax (al);
global in_string ; void in_string(char[]* si);
global comapre_strs ; int (const char* first_word[] si, const char* last_word[] bx) return cx (1 - равны, 0 - не равны);
global clear_buffer ; void (const char* buf_address[] si, int buf_size bx);
global new_line ; void new_line();
section .text
new_line:
push ax
mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
pop ax
ret
cls:
push ax
mov ah, 0x00
mov al, 0x03
int 0x10
pop ax
ret
out_char:
push ax
mov ah, 0x0e
mov al, bl
int 0x10
pop ax
ret
out_string:
push ax
mov ah, 0x0e
call __out_string_next_char
pop ax
ret
__out_string_next_char:
mov al, [si]
cmp al, 0
jz __out_string_if_zero
int 0x10
inc si
jmp __out_string_next_char
__out_string_if_zero:
ret
in_char:
push bx
mov ah, 0
int 0x16 ; Сохранение символа в регистр al
mov ah, 0x0e
mov bh, 0
mov bl, 0x07
int 0x10 ; Вывод введённого символа на экран
pop bx
ret
comapre_strs:
push si
push bx
push ax
__comapre_strs_comp:
mov ah, [bx]
cmp [si], ah
jne __comapre_strs_first_zero
inc si
inc bx
jmp __comapre_strs_comp
__comapre_strs_first_zero:
cmp byte [bx], 0
jne __comapre_strs_not_equal
mov cx, 1
pop si
pop bx
pop ax
ret
__comapre_strs_not_equal:
mov cx, 0
pop si
pop bx
pop ax
ret
clear_buffer:
; si - Адрес буфера
; bx - Колчисевто байт на очистку
push cx
mov cx, 0
__clear_buffer_loop:
cmp cx, bx
je __clear_buffer_end_loop
mov byte [si], 0
inc si
inc cx
jmp __clear_buffer_loop
__clear_buffer_end_loop:
pop cx
ret
in_string:
push ax
push cx
xor cx, cx
__input_string_loop:
mov ah, 0
int 0x16
cmp al, 0x0d ; Enter
je __input_string_enter
cmp al, 0x08 ; Backspace
je __input_string_backspace
mov [si], al
inc si
inc cx
mov ah, 0x0e
mov bh, 0
mov bl, 0x07
int 0x10
cmp cx, 255
je __input_string_enter
jmp __input_string_loop
__input_string_enter:
mov ah, 0x0e
mov al, 0x0d
mov bh, 0
mov bl, 0x07
int 0x10
mov al, 0xa
int 0x10
mov byte [si], 0
pop cx
pop ax
ret
__input_string_backspace:
cmp cx, 0
je __input_string_loop
; 0x20 ; Пробел
mov ah, 0x0e
mov al, 0x08 ; Backspace
int 0x10
mov al, 0x20 ; Пробел
int 0x10
mov al, 0x08
int 0x10
mov byte [si], 0
dec si
dec cx
jmp __input_string_loop
TermOS.asm
org 0x7c00
jmp pre_boot
pre_boot:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
mov ah, 0x02
mov al, 7 ; Количество секторов на чтение
mov ch, 0x00
mov cl, 0x02
mov dh, 0x00
mov dl, 0x80
mov bx, 0x7e00
int 0x13 ; Прерывание чтения сектора
jc read_error
; Переходим в Long Mode
;mov eax, cr4
;mov eax, 0x200
;mov cr4, eax
;mov eax, cr0
;or eax, 0x80000000
;mov cr0, eax
jmp 0x7e00 ; Переход к загруженному коду
read_error:
mov ah, 0x0e
mov al, 'R'
int 0x10
mov al, 'E'
int 0x10
mov al, 'A'
int 0x10
mov al, 'D'
int 0x10
mov al, ' '
int 0x10
mov al, 'E'
int 0x10
mov al, 'R'
int 0x10
mov al, 'R'
int 0x10
mov al, 'O'
int 0x10
mov al, 'R'
int 0x10
mov al, '!'
int 0x10
jmp $
times 510 - ($- $$) db 0
dw 0xaa55
jmp boot
boot:
call cls
call IBM_WELCOME_WINDOW
call cls
mov si, welcome
call out_string
jmp input_loop
IBM_WELCOME_WINDOW:
mov si, IBM_WELCOME
call out_string
mov ax, 0x8600
mov cx, 30
int 0x15
ret
input_loop:
mov si, buffer
mov bx, 255
call clear_buffer
mov si, prompt
call out_string
mov si, buffer
call in_string
jmp OS_callback
jmp input_loop
OS_callback:
mov si, help_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_HELP
mov si, cls_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_CLS
mov si, info_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_INFO
mov si, reboot_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_REBOOT
mov si, echo_in
mov bx, buffer
call comapre_strs
cmp cx, 1
je Callback_ECHO
jne Callback_WRONG
jmp input_loop
Callback_HELP:
mov si, help_out
call out_string
jmp input_loop
Callback_CLS:
call cls
jmp input_loop
Callback_WRONG:
mov si, wrong_command_1
call out_string
mov si, buffer
call out_string
mov si, wrong_command_2
call out_string
jmp input_loop
Callback_INFO:
mov si, info_out
call out_string
jmp input_loop
Callback_REBOOT:
mov ah, 0
int 0x19
jmp $
Callback_ECHO:
mov si, echo_out
call out_string
mov si, buffer
call in_string
mov si, buffer
call out_string
call new_line
jmp input_loop
%include "drivers/IO.asm"
welcome db "Welcome to TermOS!", 0x0a, 0x0d, "Type 'help' to get command list!", 0x0a, 0x0d, 0
prompt db "live@cd:>", 0
wrong_command_1 db "Command: '", 0
wrong_command_2 db "' not found. Type 'help' to get all commands", 0x0a, 0x0d, 0
echo_out db "Echo: ", 0
help_in db "help", 0
cls_in db "cls", 0
info_in db "info", 0
reboot_in db "reboot", 0
echo_in db "echo", 0
info_out db "TermOS x16 (Terminal Operation System 16-bit) v.0.0:", 0x0a, 0x0d, " This is operation system in development.", 0x0a, 0x0d, " Author: Daniil Kulikovskiy.", 0x0a, 0x0d, " Made in Russia!", 0x0a, 0x0d, 0
help_out db " cls - Clear screen", 0x0a, 0x0d, " info - Get system info", 0x0a, 0x0d, " reboot - Reboot computer", 0x0a, 0x0d, " echo - Write text in screen", 0x0a, 0x0d, 0
IBM_WELCOME db " ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ======== ======== ====== ======= ", 0x0a, 0x0d," ======== ========= ======== ======== ", 0x0a, 0x0d," === == === ======= ======= ", 0x0a, 0x0d," === ====== ======== ======== ", 0x0a, 0x0d," === ====== == ===== ===== == ", 0x0a, 0x0d," === == === == ========= == ", 0x0a, 0x0d," ======== ========= ===== ======= ===== ", 0x0a, 0x0d," ======== ======== ===== = ===== ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," (C) COPYRIGHT 1981, 1996 IBM CORPARATION - ALL RIGHTS RESERVED ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d," ", 0x0a, 0x0d, 0
buffer times 255 db 0
Bibliography
How to run a program without an operating system
About PC operation part 3: From turning on to fully booting Windows 10