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.

Setting OS boot priorities

Setting OS boot priorities

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.“.

The processor did not find boot devices

The processor did not find boot devices

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!

Disk read error.  The specified number of sectors to read exceeds the actual size of the executable file.

Disk read error. The specified number of sectors to read exceeds the actual size of the executable file.

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!”.

Graphical representation of the principle of command processing

Graphical representation of the principle of command processing

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
Just for fun, I added a logo "IBM" to the start screen.

For fun, I added the “IBM” logo to the start screen.

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
The resulting TermOS Operating System

The resulting TermOS Operating System

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

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *