{"id":68,"date":"2013-01-03T19:07:02","date_gmt":"2013-01-03T13:37:02","guid":{"rendered":"http:\/\/sandeepmathew.wordpress.com\/?p=34"},"modified":"2013-01-03T19:07:02","modified_gmt":"2013-01-03T13:37:02","slug":"writing-real-mode-operating-systems-for-fun-study-and-world-domination","status":"publish","type":"post","link":"https:\/\/sandeepmathew.com\/index.php\/2013\/01\/03\/writing-real-mode-operating-systems-for-fun-study-and-world-domination\/","title":{"rendered":"Writing Real mode operating systems for fun , study and world domination"},"content":{"rendered":"<p>Writing real mode operating systems is not hard at all, in fact almost anyone with a little\u00a0 knowledge of\u00a0 x86 assembler will be able to create simple real mode operating systems. The idea of this post is to get you started with real mode operating system development. In this tutorial we will build a\u00a0 simple yet functional real mode operating system.<\/p>\n<p><span style=\"text-decoration:underline;\">Tools of\u00a0 Trade<\/span><\/p>\n<p>What we need to create a simple real mode operating system is just an assembler and a x86 emulator to test the operating system you wrote.\u00a0 Another thing you can do is just\u00a0 have\u00a0 MS DOS running is one of the emulators and test your .COM files in the dos box before run in your operating system. Sounds fun ain&#8217;t\u00a0 it ?\u00a0 So what will we be using<\/p>\n<ol>\n<li>FASM as the assembler : http:\/\/www.flatassembler.net<\/li>\n<li>An emulator Microsoft Virtual PC : http:\/\/www.microsoft.com\/downloads\/en\/details.aspx?FamilyID=04d26402-3199-48a3-afa2-2dc0b40a73b6&amp;displaylang=en<\/li>\n<li>Dosbox for testing : <a href=\"www.dosbox.com\"> www.dosbox.com<\/a><\/li>\n<\/ol>\n<p><span style=\"text-decoration:underline;\">Learning real mode x86\u00a0 assembly <\/span><\/p>\n<p>Learning how to hack a few x86 instructions is a handy skill to have . There are plenty of resources available only to learn x86 assembly language programming .\u00a0 My recommendations are as follows<\/p>\n<ol>\n<li>Emu8086 &#8211;\u00a0 Emu8086 is a great platform to learn x86 assembly language , tutorials are simple and it even includes an os development tutorial.\u00a0 See : http:\/\/ziplib.com\/emu8086\/<\/li>\n<li>Ketman&#8217;s utilites\u00a0\u00a0 &#8211; ketmans<\/li>\n<\/ol>\n<p><span style=\"text-decoration:underline;\">What the heck is real mode and why is real mode OS development easier to get started ?<\/span><\/p>\n<p>When an IBM x86 PC starts , it actually starts in real mode. You basically have access to only 1 MB of memory and you work with 16 bit registers.\u00a0\u00a0 The best part of real mode is that you can make use of BIOS services to get most of the work done, you need not write drivers display , keyboard and most of the other stuff. All you have to do\u00a0 get most of hardware working is to invoke the appropriate real mode interrupt.<\/p>\n<p>eg<\/p>\n<p>[sourcecode language=&#8221;text&#8221;]<\/p>\n<p>WAIT_FOR_KEY_PRESS:<br \/>\n XOR AX , AX<br \/>\n INT 16H<\/p>\n<p>[\/sourcecode]<\/p>\n<p>Here 16h is a BIOS service that helps you to interact with the keyboard. For a details about BIOS services you may take look at the ralf brown interrupt list. <a href=\"http:\/\/www.ctyme.com\/rbrown.htm\"> Professor Ralf Brown&#8217;s Interrupt List ,<\/a><\/p>\n<p>You work with 16 bit registers, you have access to 2^16 = 64kbytes of memory. However you can still access 1MB memory using 2 registers. This is called segment offset addressing or real mode segmentation. One of the segment registers act as a base address ( compare it to a page in a book ) and offset registers\u00a0 ( like line within a page ) act as offset from the base, so the effective address really is\u00a0 =\u00a0 16 * SEGMENT_ADRESS + OFFSET_ADDRESS.\u00a0 In many operations segment registers are implicitly\u00a0 implied eg SS:SP , CS for IP , DS : DI , ES : SI\u00a0 eg . However you can override the implied segment registers with an SEGMENT override prefix eg [ES:BX]\u00a0 . This means you\u00a0 treat ES as a segment and BX as the offset .<\/p>\n<p><span style=\"text-decoration:underline;\">Starting Simple :- A simple boot loader<\/span><\/p>\n<p>The first sector of the floppy is appended with the boot signature 0xaa55, then it will be executed by the computer and it will be able to use the bios services. That&#8217;s all you need to do to get a boot loader working. I am showing an example boot loader . I am just pasting an example bootloader from osdev.org. A more advanced boot loader would load a file\u00a0 (kernel) into memory and jump to the first executable instruction. Take look at the freedos bootloader to see how it is done.<\/p>\n<p>[sourcecode langauge=&#8221;text&#8221;]<\/p>\n<p>mov ax, 0x07C0  ; set up segments<br \/>\n   mov ds, ax<br \/>\n   mov es, ax<\/p>\n<p>   mov si, welcome<br \/>\n   call print_string<\/p>\n<p> mainloop:<br \/>\n   mov si, prompt<br \/>\n   call print_string<\/p>\n<p>   mov di, buffer<br \/>\n   call get_string<\/p>\n<p>   mov si, buffer<br \/>\n   cmp byte [si], 0  ; blank line?<br \/>\n   je mainloop       ; yes, ignore it<\/p>\n<p>   mov si, buffer<br \/>\n   mov di, cmd_hi  ; &quot;hi&quot; command<br \/>\n   call strcmp<br \/>\n   jc .helloworld<\/p>\n<p>   mov si, buffer<br \/>\n   mov di, cmd_help  ; &quot;help&quot; command<br \/>\n   call strcmp<br \/>\n   jc .help<\/p>\n<p>   mov si,badcommand<br \/>\n   call print_string<br \/>\n   jmp mainloop<\/p>\n<p> .helloworld:<br \/>\n   mov si, msg_helloworld<br \/>\n   call print_string<\/p>\n<p>   jmp mainloop<\/p>\n<p> .help:<br \/>\n   mov si, msg_help<br \/>\n   call print_string<\/p>\n<p>   jmp mainloop<\/p>\n<p> welcome db &#8216;Welcome to My OS!&#8217;, 0x0D, 0x0A, 0<br \/>\n msg_helloworld db &#8216;Hello OSDev World!&#8217;, 0x0D, 0x0A, 0<br \/>\n badcommand db &#8216;Bad command entered.&#8217;, 0x0D, 0x0A, 0<br \/>\n prompt db &#8216;&gt;&#8217;, 0<br \/>\n cmd_hi db &#8216;hi&#8217;, 0<br \/>\n cmd_help db &#8216;help&#8217;, 0<br \/>\n msg_help db &#8216;My OS: Commands: hi, help&#8217;, 0x0D, 0x0A, 0<br \/>\n buffer times 64 db 0<\/p>\n<p> ; ================<br \/>\n ; calls start here<br \/>\n ; ================<\/p>\n<p> print_string:<br \/>\n   lodsb        ; grab a byte from SI<\/p>\n<p>   or al, al  ; logical or AL by itself<br \/>\n   jz .done   ; if the result is zero, get out<\/p>\n<p>   mov ah, 0x0E<br \/>\n   int 0x10      ; otherwise, print out the character!<\/p>\n<p>   jmp print_string<\/p>\n<p> .done:<br \/>\n   ret<\/p>\n<p> get_string:<br \/>\n   xor cl, cl<\/p>\n<p> .loop:<br \/>\n   mov ah, 0<br \/>\n   int 0x16   ; wait for keypress<\/p>\n<p>   cmp al, 0x08    ; backspace pressed?<br \/>\n   je .backspace   ; yes, handle it<\/p>\n<p>   cmp al, 0x0D  ; enter pressed?<br \/>\n   je .done      ; yes, we&#8217;re done<\/p>\n<p>   cmp cl, 0x3F  ; 63 chars inputted?<br \/>\n   je .loop      ; yes, only let in backspace and enter<\/p>\n<p>   mov ah, 0x0E<br \/>\n   int 0x10      ; print out character<\/p>\n<p>   stosb  ; put character in buffer<br \/>\n   inc cl<br \/>\n   jmp .loop<\/p>\n<p> .backspace:<br \/>\n   cmp cl, 0\t; beginning of string?<br \/>\n   je .loop\t; yes, ignore the key<\/p>\n<p>   dec di<br \/>\n   mov byte [di], 0\t; delete character<br \/>\n   dec cl\t\t; decrement counter as well<\/p>\n<p>   mov ah, 0x0E<br \/>\n   mov al, 0x08<br \/>\n   int 10h\t\t; backspace on the screen<\/p>\n<p>   mov al, &#8216; &#8216;<br \/>\n   int 10h\t\t; blank character out<\/p>\n<p>   mov al, 0x08<br \/>\n   int 10h\t\t; backspace again<\/p>\n<p>   jmp .loop\t; go to the main loop<\/p>\n<p> .done:<br \/>\n   mov al, 0\t; null terminator<br \/>\n   stosb<\/p>\n<p>   mov ah, 0x0E<br \/>\n   mov al, 0x0D<br \/>\n   int 0x10<br \/>\n   mov al, 0x0A<br \/>\n   int 0x10\t\t; newline<\/p>\n<p>   ret<\/p>\n<p> strcmp:<br \/>\n .loop:<br \/>\n   mov al, [si]   ; grab a byte from SI<br \/>\n   mov bl, [di]   ; grab a byte from DI<br \/>\n   cmp al, bl     ; are they equal?<br \/>\n   jne .notequal  ; nope, we&#8217;re done.<\/p>\n<p>   cmp al, 0  ; are both bytes (they were equal before) null?<br \/>\n   je .done   ; yes, we&#8217;re done.<\/p>\n<p>   inc di     ; increment DI<br \/>\n   inc si     ; increment SI<br \/>\n   jmp .loop  ; loop!<\/p>\n<p> .notequal:<br \/>\n   clc  ; not equal, clear the carry flag<br \/>\n   ret<\/p>\n<p> .done:<br \/>\n   stc  ; equal, set the carry flag<br \/>\n   ret<\/p>\n<p>   times 510-($-$$) db 0<br \/>\n   dw 0AA55h ; some BIOSes require this signature<\/p>\n<p>[\/sourcecode]<\/p>\n<p><span style=\"text-decoration:underline;\">Understanding Fat File System<\/span><\/p>\n<p>A fa12 file system looks like this.<\/p>\n<p>BPB + Boot Code ] [ Fat Table 1] [ Fat Table 2] [Root Directory Area] [ Data]<br \/>\nEach file has an entry in the root directory area , One of the main fields of the root directory area is the<br \/>\nthe first sector number. Fat table contains the next sector indexed by sector number . Fat Table2 is a<br \/>\ncopy of Fat Table1 for recovery purposes. Fat Table1 [current_sector] = next sector. ( Note that fat12<br \/>\ndoes packs 2 12bit entries into a 24 bit entry to save space , but it&#8217;s explained easily as above.).<\/p>\n<p><a href=\"http:\/\/sandeepmathew.wordpress.com\/wp-content\/uploads\/2013\/01\/fat12_overview.pdf\">FAT12_overview <\/a><\/p>\n<p><span style=\"text-decoration:underline;\">Implementing a simple shell<\/span><\/p>\n<p>A shell accepts command from the user and takes appropriate actions. Below is a shell implementation<\/p>\n<p>of my hobby operating system.<\/p>\n<p>[sourcecode language=&#8221;text&#8221;]<br \/>\n#########################################################################################################<br \/>\n;# #<br \/>\n;# shell.asm #<br \/>\n;# This implements the shell . This is a really simple shell .It gets a string from the user #<br \/>\n;# and checks whether it is one of the commands known to shell ,if it is one them it just calls #<br \/>\n;# the corresponding functions , else it check that there exists an external file in the disk #<br \/>\n;# that has a same name as the input . If it exits , its loaded and executed #<br \/>\n;#########################################################################################################<\/p>\n<p>;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n; procedure shell_initialize |<br \/>\n; performs various operations before starting the shell . |<br \/>\n; (1) print the Sandman Logo \ud83d\ude42 |<br \/>\n; |<br \/>\n;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\nshell_initialize:<br \/>\n                mov [save_address],dx<br \/>\n                mov [cs_save],ax<br \/>\n                push cs<br \/>\n                pop ds<br \/>\n                push ds<br \/>\n                pop es<br \/>\n                cld<\/p>\n<p>                mov si , initial_msg<br \/>\n                call print_string<br \/>\n                cli<br \/>\n                call install_interrupts<br \/>\n                sti<br \/>\nshell_loop:<br \/>\n         call print_prompt<br \/>\n         mov di , cmd_buffer<br \/>\n         mov cx , 13<br \/>\n         call read_string<br \/>\n         mov di , cmd_buffer<br \/>\n         call to_upper<br \/>\n         mov si , cmd_buffer<br \/>\n         mov di , cmd_cls<br \/>\n         stc<br \/>\n         call string_equal<br \/>\n         jnc .do_cls<\/p>\n<p>         mov si , cmd_buffer<br \/>\n         mov di , cmd_help<br \/>\n         stc<br \/>\n         call string_equal<br \/>\n         jnc .do_help<\/p>\n<p>         mov si , cmd_buffer<br \/>\n         mov di , cmd_dir<br \/>\n         stc<br \/>\n         call string_equal<br \/>\n         jnc .do_dir<\/p>\n<p>    .load_prog:<\/p>\n<p>       call ConvertFileName<\/p>\n<p>       stc<br \/>\n       mov di , RootConvertedFileName<br \/>\n       add di , 8<br \/>\n       mov si , com_ext<br \/>\n       call string_equal<br \/>\n       jnc .file_extension_ok<\/p>\n<p>       stc<br \/>\n       mov di , RootConvertedFileName<br \/>\n       add di , 8<br \/>\n       mov si , exe_ext<br \/>\n       call string_equal<br \/>\n       jnc .file_extension_ok<\/p>\n<p>       jmp shell_loop<br \/>\n.file_extension_ok:<\/p>\n<p>        mov ax,0x80<br \/>\n        shl ax, 6<br \/>\n        mov word[end_memory],ax<br \/>\n        int 12h<br \/>\n        shl ax,6<br \/>\n        mov word[top_memory],ax<\/p>\n<p>        sub ax,512 \/ 16<br \/>\n        mov es,ax<br \/>\n        sub ax,2048 \/ 16<br \/>\n        mov ss,ax<br \/>\n        mov sp,2048<\/p>\n<p>        mov cx, 11<br \/>\n        mov si, RootConvertedFileName<br \/>\n        mov di,[save_address]<br \/>\n        rep movsb<\/p>\n<p>        push es<br \/>\n        mov bx,[cs_save]<br \/>\n        push bx<br \/>\n        xor bx,bx<br \/>\n        retf<br \/>\n        jmp $<\/p>\n<p>    .do_cls:<br \/>\n         xor dx , dx<br \/>\n         call set_cursor<br \/>\n         call clear_screen<br \/>\n         jmp shell_loop<\/p>\n<p>    .do_help:<br \/>\n         mov si , help_msg<br \/>\n         call print_string<br \/>\n         jmp shell_loop<br \/>\n    .do_dir:<br \/>\n         call clear_screen<br \/>\n         call DirPrintFile<br \/>\n         jmp shell_loop<\/p>\n<p>;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br \/>\n; procedure print_prompt : |<br \/>\n; prints the prompt to the user . |<br \/>\n; input : none |<br \/>\n; output : prints the prompt |<br \/>\n;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br \/>\nprint_prompt:<br \/>\n         mov si , prompt<br \/>\n         call print_string<br \/>\n         ret<\/p>\n<p>cmd_cls db        &#8216;CLS&#8217;,0<br \/>\ncmd_help db        &#8216;HELP&#8217;,0<br \/>\ncmd_dir db        &#8216;DIR&#8217;,0<br \/>\nprompt         db &#8216;$&#8217; ,0<br \/>\ncmd_buffer: times 14 db 0<br \/>\ncom_ext db &#8216;COM&#8217;,0<br \/>\nexe_ext db &#8216;EXE&#8217;,0<\/p>\n<p>initial_msg db &#8216;Welcome to 1K-DOS \ud83d\ude42 &#8216;,13,10, &#8216; ^ ^ ^&#8217;,13,10, &#8216; ( *|* )&#8217;,13,10, &#8216; \/ ~ \\&#8217;,13,10, &#8216; \/ \\&#8217;,13,10, &#8216; &#8212;&#8212;&#8212;&#8216;,13,10,&#8217; | |&#8217;,13,10, &#8216; _| _| by S@ndM@n &#8216;,13,10 ,0<br \/>\nhelp_msg db 13 , 10 ,&#8217;CLS &#8211; Clears the Screen &#8216; ,13 , 10 , &#8216;HELP &#8211; Displays This Info &#8216; , 13,10 , &#8216;&lt;FILENAME&gt; &#8211; Executes Given File&#8217; ,13 , 10,&#8217;DIR -List Contents of Root Directory&#8217; ,13 , 10, 0<br \/>\nsave_address dw 0<br \/>\ncs_save         dw 0<\/p>\n<p>include &#8216;util.asm<\/p>\n<p>[\/sourcecode]<\/p>\n<p><span style=\"text-decoration:underline;\">Executing programs<\/span><\/p>\n<p>What you need to do is load the program into memory ( since it a fat12 file , we by now know how to load the file to memory ) and perform relocation if necessary . They jump to beginning of the first executable instruction. in the program. This is illustrated by the following code : ( taken from alexi a frounze , bootcode)<\/p>\n<p>[sourcecode language=&#8221;text&#8221;]<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Load entire a program ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;<\/p>\n<p>ReadNextCluster:<br \/>\n        call    ReadCluster<br \/>\n        cmp     si, 0FF8h<br \/>\n        jc      ReadNextCluster         ; if not End Of File<\/p>\n<p>;;;;;;;;;;;;;;;;;;;<br \/>\n;; Type checking ;;<br \/>\n;;;;;;;;;;;;;;;;;;;<\/p>\n<p>        cli                             ; for stack adjustments<\/p>\n<p>        mov     ax, ImageLoadSeg<br \/>\n        mov     es, ax<\/p>\n<p>        cmp     word [es:0], 5A4Dh      ; &quot;MZ&quot; signature?<br \/>\n        je      RelocateEXE             ; yes, it&#8217;s an EXE program<\/p>\n<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Setup and Run COM program ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<\/p>\n<p>        mov     ax, es<br \/>\n        sub     ax, 10h                 ; &quot;org 100h&quot; stuff \ud83d\ude42<br \/>\n        mov     es, ax<br \/>\n        mov     ds, ax<br \/>\n        mov     ss, ax<br \/>\n        xor     sp, sp<br \/>\n        push    es<br \/>\n        push    word 100h<br \/>\n        jmp     Run<\/p>\n<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Relocate, setup and run EXE program ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<\/p>\n<p>RelocateEXE:<br \/>\n        mov     ds, ax<\/p>\n<p>        add     ax, [ds:08h]            ; ax = image base<br \/>\n        mov     cx, [ds:06h]            ; cx = reloc items<br \/>\n        mov     bx, [ds:18h]            ; bx = reloc table pointer<\/p>\n<p>        jcxz    RelocationDone<\/p>\n<p>ReloCycle:<br \/>\n        mov     di, [ds:bx]             ; di = item ofs<br \/>\n        mov     dx, [ds:bx+2]           ; dx = item seg (rel)<br \/>\n        add     dx, ax                  ; dx = item seg (abs)<\/p>\n<p>        push    ds<br \/>\n        mov     ds, dx                  ; ds = dx<br \/>\n        add     [ds:di], ax             ; fixup<br \/>\n        pop     ds<\/p>\n<p>        add     bx, 4                   ; point to next entry<br \/>\n        loop    ReloCycle<\/p>\n<p>RelocationDone:<\/p>\n<p>        mov     bx, ax<br \/>\n        add     bx, [ds:0Eh]<br \/>\n        mov     ss, bx                  ; ss for EXE<br \/>\n        mov     sp, [ds:10h]            ; sp for EXE<\/p>\n<p>        add     ax, [ds:16h]            ; cs<br \/>\n        push    ax<br \/>\n        push    word [ds:14h]           ; ip<br \/>\nRun:<br \/>\n        mov     dl, [cs:bsDriveNumber]  ; let program know boot drive<br \/>\n        sti<br \/>\n        retf<\/p>\n<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Reads a FAT12 cluster      ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Inout:  ES:BX -&gt; buffer    ;;<br \/>\n;;         SI = cluster no    ;;<br \/>\n;; Output: SI = next cluster  ;;<br \/>\n;;         ES:BX -&gt; next addr ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<\/p>\n<p>ReadCluster:<br \/>\n        mov     bp, sp<\/p>\n<p>        lea     ax, [si-2]<br \/>\n        xor     ch, ch<br \/>\n        mov     cl, [bpbSectorsPerCluster]<br \/>\n                ; cx = sector count<br \/>\n        mul     cx<\/p>\n<p>        add     ax, [ss:bp+1*2]<br \/>\n        adc     dx, [ss:bp+2*2]<br \/>\n                ; dx:ax = LBA<\/p>\n<p>        call    ReadSector<\/p>\n<p>        mov     ax, [bpbBytesPerSector]<br \/>\n        shr     ax, 4                   ; ax = paragraphs per sector<br \/>\n        mul     cx                      ; ax = paragraphs read<\/p>\n<p>        mov     cx, es<br \/>\n        add     cx, ax<br \/>\n        mov     es, cx                  ; es:bx updated<\/p>\n<p>        mov     ax, 3<br \/>\n        mul     si<br \/>\n        shr     ax, 1<br \/>\n        xchg    ax, si                  ; si = cluster * 3 \/ 2<\/p>\n<p>        push    ds<br \/>\n        mov     ds, [ss:bp+3*2]         ; ds = FAT segment<br \/>\n        mov     si, [ds:si]             ; si = next cluster<br \/>\n        pop     ds<\/p>\n<p>        jnc     ReadClusterEven<\/p>\n<p>        shr     si, 4<\/p>\n<p>ReadClusterEven:<br \/>\n        and     si, 0FFFh               ; mask cluster value<br \/>\nReadClusterDone:<br \/>\n        ret<\/p>\n<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Reads a sector using BIOS Int 13h fn 2 ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<br \/>\n;; Input:  DX:AX = LBA                    ;;<br \/>\n;;         CX    = sector count           ;;<br \/>\n;;         ES:BX -&gt; buffer address        ;;<br \/>\n;; Output: CF = 1 if error                ;;<br \/>\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<\/p>\n<p>ReadSector:<br \/>\n        pusha<\/p>\n<p>ReadSectorNext:<br \/>\n        mov     di, 5                   ; attempts to read<\/p>\n<p>ReadSectorRetry:<br \/>\n        pusha<\/p>\n<p>        div     word [bpbSectorsPerTrack]<br \/>\n                ; ax = LBA \/ SPT<br \/>\n                ; dx = LBA % SPT         = sector &#8211; 1<\/p>\n<p>        mov     cx, dx<br \/>\n        inc     cx<br \/>\n                ; cx = sector no.<\/p>\n<p>        xor     dx, dx<br \/>\n        div     word [bpbHeadsPerCylinder]<br \/>\n                ; ax = (LBA \/ SPT) \/ HPC = cylinder<br \/>\n                ; dx = (LBA \/ SPT) % HPC = head<\/p>\n<p>        mov     ch, al<br \/>\n                ; ch = LSB 0&#8230;7 of cylinder no.<br \/>\n        shl     ah, 6<br \/>\n        or      cl, ah<br \/>\n                ; cl = MSB 8&#8230;9 of cylinder no. + sector no.<\/p>\n<p>        mov     dh, dl<br \/>\n                ; dh = head no.<\/p>\n<p>        mov     dl, [bsDriveNumber]<br \/>\n                ; dl = drive no.<\/p>\n<p>        mov     ax, 201h<br \/>\n                                        ; al = sector count<br \/>\n                                        ; ah = 2 = read function no.<\/p>\n<p>        int     13h                     ; read sectors<br \/>\n        jnc     ReadSectorDone          ; CF = 0 if no error<\/p>\n<p>        xor     ah, ah                  ; ah = 0 = reset function<br \/>\n        int     13h                     ; reset drive<\/p>\n<p>        popa<br \/>\n        dec     di<br \/>\n        jnz     ReadSectorRetry         ; extra attempt<br \/>\n        jmp     short ErrRead<\/p>\n<p>ReadSectorDone:<br \/>\n        popa<br \/>\n        dec     cx<br \/>\n        jz      ReadSectorDone2         ; last sector<\/p>\n<p>        add     bx, [bpbBytesPerSector] ; adjust offset for next sector<br \/>\n        add     ax, 1<br \/>\n        adc     dx, 0                   ; adjust LBA for next sector<br \/>\n        jmp     short ReadSectorNext<\/p>\n<p>ReadSectorDone2:<br \/>\n        popa<br \/>\n        ret<\/p>\n<p>[\/sourcecode]<\/p>\n<p><span style=\"text-decoration:underline;\">Implementing system calls or writing your own interrupt handler<\/span><\/p>\n<p>Writing real mode interrupt handler is very easy, all you need to do is set the address of the of the interrupt routines in the real mode interrupt table. It is shown in the code below.<\/p>\n<p>[sourcecode language=&#8221;text&#8221;]<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n; procedure install_interrupts : |<br \/>\n; The main goal of this procedure is to initialize the real mode |<br \/>\n; intterrupt table . The real mode interrupt table is initialized |<br \/>\n; as follows [0000 : int_no * 4 ] := handler offset address and |<br \/>\n; [0000 : int_no *4 +2 ] := handler segment address . |<br \/>\n; |<br \/>\n; input : none |<br \/>\n; output : sets the real mode interrupt table |<br \/>\n;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<\/p>\n<p>install_interrupts:<br \/>\n                 push ax<br \/>\n                 push es<br \/>\n                 cli<br \/>\n                 xor ax , ax<br \/>\n                 mov es , ax<br \/>\n                 ; install the int20 interrupt handler<br \/>\n                 mov WORD [es : 0x20 *4] , int20_handler<br \/>\n                 mov WORD [es : 0x20 * 4 + 2] , cs<br \/>\n                 ; install the int21 interrupt handler<br \/>\n                 mov WORD [es : 0x21 *4 ] ,int21_handler<br \/>\n                 mov WORD [es : 0x21 *4 + 2],cs<br \/>\n                 sti<br \/>\n                 pop es<br \/>\n                 pop ax<br \/>\n                 ret<\/p>\n<p>[\/sourcecode]<\/p>\n<p><span style=\"text-decoration:underline;\">Implementing Multitasking in real mode<\/span><\/p>\n<p>This link explains it very well\u00a0 : http:\/\/nw08.american.edu\/~mblack\/projects\/OSProjectE.doc<\/p>\n<p><span style=\"text-decoration:underline;\">Books on real mode OS development<\/span><\/p>\n<p>FreeDos kernel<\/p>\n<p>Dissecting DOS<\/p>\n<p><span style=\"text-decoration:underline;\">Operating\u00a0 System Source code worth reading<\/span><\/p>\n<p>MikeOS Operating System :-\u00a0 http:\/\/mikeos.berlios.de\/<\/p>\n<p>Public Domain DOS &#8211; pdos86\u00a0 :- http:\/\/sourceforge.net\/projects\/pdos\/<\/p>\n<p>Free DOS Operating System &#8211; http:\/\/sourceforge.net\/projects\/freedos\/<\/p>\n<p>RxDOS Operating System &#8211;\u00a0 http:\/\/rxdos.sourceforge.net\/<\/p>\n<p>Pico Embedded RTOS :-http:\/\/sourceforge.net\/projects\/picoos\/?source=directory<\/p>\n<p>PS : This article has become very messy because i could not really devote much time to it , i will work on it when i get some more time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Writing real mode operating systems is not hard at all, in fact almost anyone with a little\u00a0 knowledge of\u00a0 x86 assembler will be able to create simple real mode operating systems. The idea of this post is to get you started with real mode operating system development. In this tutorial we will build a\u00a0 simple [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6],"tags":[],"_links":{"self":[{"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/posts\/68"}],"collection":[{"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/comments?post=68"}],"version-history":[{"count":0,"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/posts\/68\/revisions"}],"wp:attachment":[{"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/media?parent=68"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/categories?post=68"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sandeepmathew.com\/index.php\/wp-json\/wp\/v2\/tags?post=68"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}