{"id":165,"date":"2009-05-07T00:01:25","date_gmt":"2009-05-07T08:01:25","guid":{"rendered":"http:\/\/www.pagetable.com\/?p=165"},"modified":"2009-05-07T00:01:25","modified_gmt":"2009-05-07T08:01:25","slug":"the-dos-10-boot-sector","status":"publish","type":"post","link":"https:\/\/www.pagetable.com\/?p=165","title":{"rendered":"Reverse-Engineering DOS 1.0 &#8211; Part 1: The Boot Sector"},"content":{"rendered":"<p><i>Update<\/i>: The source is available at <a href=\"https:\/\/github.com\/mist64\/msdos1\">github.com\/mist64\/msdos1<\/a><\/p>\n<p>The bootsector of DOS 1.0 is celebrating its 28th birthday today (it contains the timestamp &#8220;7-May-81&#8221;), so let&#8217;s look at it more closely.<\/p>\n<p>Here it is:<\/p>\n<pre>\n00000000  eb 2f 14 00 00 00 60 00  20 37 2d 4d 61 79 2d 38  |........ 7-May-8|\n00000010  31 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |1...............|\n00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\n00000030  00 fa 8c c8 8e d8 ba 00  00 8e d2 bc 00 7c fb a1  |................|\n00000040  06 7c 8e d8 8e c0 ba 00  00 8b c2 cd 13 72 41 e8  |................|\n00000050  58 00 72 fb 2e 8b 0e 02  7c 51 bb 00 00 33 d2 b9  |................|\n00000060  08 00 be 01 00 56 b0 01  b4 02 cd 13 72 22 5e 58  |................|\n00000070  e8 e7 00 2b c6 74 14 fe  c5 b1 01 be 08 00 3b c6  |................|\n00000080  73 04 8b f0 eb 01 96 56  50 eb dd 2e ff 2e 04 7c  |................|\n00000090  be 44 7d b8 42 7d 50 32  ff ac 24 7f 74 0b 56 b4  |................|\n000000a0  0e bb 07 00 cd 10 5e eb  f0 c3 bb 00 00 b9 04 00  |................|\n000000b0  b8 01 02 cd 13 1e 72 34  8c c8 8e d8 bf 00 00 b9  |................|\n000000c0  0b 00 26 80 0d 20 26 80  8d 20 00 20 47 e2 f3 bf  |................|\n000000d0  00 00 be 76 7d b9 0b 00  fc f3 a6 75 0f bf 20 00  |................|\n000000e0  be 82 7d b9 0b 00 f3 a6  75 02 1f c3 be f9 7c e8  |................|\n000000f0  a5 ff b4 00 cd 16 1f f9  c3 0d 0a 4e 6f 6e 2d 53  |...........Non-S|\n00000100  79 73 74 65 6d 20 64 69  73 6b 20 6f 72 20 64 69  |ystem disk or di|\n00000110  73 6b 20 65 72 72 6f f2  0d 0a 52 65 70 6c 61 63  |sk erro?..Replac|\n00000120  65 20 61 6e 64 20 73 74  72 69 6b 65 20 61 6e 79  |e and strike any|\n00000130  20 6b 65 79 20 77 68 65  6e 20 72 65 61 64 f9 0d  | key when read?.|\n00000140  0a 00 cd 18 0d 0a 44 69  73 6b 20 42 6f 6f 74 20  |......Disk Boot |\n00000150  66 61 69 6c 75 72 e5 0d  0a 00 50 52 8b c6 bf 00  |failur?.........|\n00000160  02 f7 e7 03 d8 5a 58 c3  52 6f 62 65 72 74 20 4f  |........Robert O|\n00000170  27 52 65 61 72 20 69 62  6d 62 69 6f 20 20 63 6f  |'Rear ibmbio  co|\n00000180  6d b0 69 62 6d 64 6f 73  20 20 63 6f 6d b0 c9 00  |m.ibmdos  com...|\n00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\n*\n00000200\n<\/pre>\n<p>DOS 1.0 shipped on a 160 KB single sided disk. The boot code in the IBM PC&#8217;s BIOS loaded the first sector into RAM at segment 0x0000, offset 0x7C00 and ran it. Later versions of BIOS checked for 0xAA55 in the last word of the bootsector, but the first version did not. Note that DOS 1.0 is also pre-BIOS Parameter Block, i.e. the bootsector does not contain any information about the physical layout of the disk, since there was only a single disk size.<\/p>\n<p>What the boot sector is supposed to do is read &#8220;IBMBIO.COM&#8221; and &#8220;IBMDOS.COM&#8221; into RAM and run them &#8211; these are the DOS system files for machine abstraction and DOS API, respectively. In MS-DOS, they would be called &#8220;IO.SYS&#8221; and &#8220;MSDOS.SYS&#8221;.<\/p>\n<p>But the DOS 1.0 bootsector takes quite a lot of shortcuts. It assumes it&#8217;s always a 40 track, 8 sectors single-sided disk and the two files occupy the first sectors of the data area contiguously &#8211; something that SYS.COM could guarantee when making a disk bootable.<\/p>\n<p>So the bootsector first loads the first sector of the root directory (hardcoded to track 0, sector 4) and compares the first two entries with &#8220;IBMBIO.COM&#8221; and &#8220;IBMDOS.COM&#8221;. For some reason, the comparison is case-insensitive, although DOS only allows uppercase filenames.<\/p>\n<pre>\n00000600  49 42 4d 42 49 4f 20 20  43 4f 4d 06 00 00 00 00  |IBMBIO  COM.....|\n00000610  00 00 00 00 00 00 00 00  f7 02 02 00 80 07 00 00  |................|\n00000620  49 42 4d 44 4f 53 20 20  43 4f 4d 06 00 00 00 00  |IBMDOS  COM.....|\n00000630  00 00 00 00 00 00 00 00  0d 03 06 00 00 19 00 00  |................|\n<\/pre>\n<p>If they are not there, it prompts the user to replace the disk and tries again. Otherwise, it loads 20 sectors starting from track 0, sector 8 to segment 0x0060, offset 0x0000 into memory and jumps there.<\/p>\n<p>0x60:0x0000 is the same as the linear address 0x0600. On the IBM PC, 0x0000 to 0x03FF are occupied by the interrupts vectors, 0x0400 to 0x4FF is used by BIOS for its variables, and DOS 1.0 uses 0x500 to 0x5FF as the &#8220;DOS Communication Area&#8221;, so code can start at 0x0600.<\/p>\n<pre>\n00000e00  e9 62 01 e9 6d 00 e9 b2  00 e9 d8 00 e9 e8 00 e9  |................|\n00000e10  24 01 e9 3a 01 e9 51 03  e9 52 03 e9 44 01 b1 00  |................|\n00000e20  22 00 42 49 4f 53 20 56  65 72 73 69 6f 6e 20 31  |..BIOS Version 1|\n00000e30  2e 30 30 a0 32 32 2d 4a  75 6c 2d 38 31 00 0d 0a  |.00.22-Jul-81...|\n<\/pre>\n<p>These are the first few bytes of IBMBIO.COM. Its birthday is about six weeks from now, but I am going to post about its internals next week.<\/p>\n<p>Let us finally look at the complete commented disassembly of the boot sector. It compiles with NASM, but will emit a few bytes differently because of variations in the assembly encoding &#8211; but variations in size have been compensated wit NOPs. It is actually quite easy to read.<\/p>\n<pre>\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n<font color=#007400>; DOS 1.0 Boot Sector (disk image MD5 73c919cecadf002a7124b7e8bfe3b5ba)<\/font>\n<font color=#007400>;   http:\/\/www.pagetable.com\/<\/font>\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\n                org <font color=#1c00cf>0x7C00<\/font>\n\n                jmp     short start\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nos_numsectors   dw <font color=#1c00cf>20<\/font>                   <font color=#007400>; how many sectors to read<\/font>\nos_offset       dw <font color=#1c00cf>0<\/font>                    <font color=#007400>; segment to load code into<\/font>\nos_segment      dw <font color=#1c00cf>0x60<\/font>                 <font color=#007400>; offset to load code into<\/font>\n\n                db <font color=#c41a16>\" 7-May-81\"<\/font>,<font color=#1c00cf>0<\/font>        <font color=#007400>; timestamp<\/font>\n                times <font color=#1c00cf>31<\/font> db <font color=#1c00cf>0<\/font>           <font color=#007400>; padding<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nstart           cli\n                mov     ax, cs\n                mov     ds, ax          <font color=#007400>; DS := CS<\/font>\n                mov     dx, <font color=#1c00cf>0<\/font>\n                mov     ss, dx          <font color=#007400>; SS := 0000<\/font>\n                mov     sp, <font color=#1c00cf>0x7C00<\/font>      <font color=#007400>; stack below code<\/font>\n                sti\n                mov     ax, [os_segment]\n                mov     ds, ax\n                mov     es, ax          <font color=#007400>; ES := DS := where to load DOS<\/font>\n                mov     dx, <font color=#1c00cf>0<\/font>\n                mov     ax, dx\n                int     <font color=#1c00cf>0x13<\/font>            <font color=#007400>; reset drive 0<\/font>\n                jc      disk_error\nagain           call    check_sys_files <font color=#007400>; check for presence of IBMDOS\/IBMBIO<\/font>\n                jc      again           <font color=#007400>; not found, try another disk<\/font>\n                mov     cx, [cs:os_numsectors]\n                push    cx              <font color=#007400>; remaining sectors<\/font>\n                mov     bx, <font color=#1c00cf>0<\/font>\n                xor     dx, dx          <font color=#007400>; drive 0, head 0<\/font>\n                mov     cx, <font color=#1c00cf>8<\/font>           <font color=#007400>; track 0, sector 8<\/font>\n                mov     si, <font color=#1c00cf>1<\/font>           <font color=#007400>; read 1 sector in first found<\/font>\n                push    si\n                mov     al, <font color=#1c00cf>1<\/font>           <font color=#007400>; 1 sector<\/font>\nread_loop       mov     ah, <font color=#1c00cf>2<\/font>\n                int     <font color=#1c00cf>0x13<\/font>            <font color=#007400>; read sector(s)<\/font>\n                jc      disk_error\n                pop     si              <font color=#007400>; sectors read<\/font>\n                pop     ax              <font color=#007400>; remaining sectors<\/font>\n                call    add_si_sectors  <font color=#007400>; bx += si*512<\/font>\n                sub     ax, si          <font color=#007400>; remaining -= read<\/font>\n                jz      done                <font color=#007400>; none left<\/font>\n                inc     ch              <font color=#007400>; next track<\/font>\n                mov     cl, <font color=#1c00cf>1<\/font>           <font color=#007400>; start at sector 1<\/font>\n                mov     si, <font color=#1c00cf>8<\/font>           <font color=#007400>; read up to 8 sectors<\/font>\n                cmp     ax, si          <font color=#007400>; how many are left to read?<\/font>\n                jae     at_least_8_left <font color=#007400>; at least 8<\/font>\n                mov     si, ax          <font color=#007400>; only read remaining amount<\/font>\n                jmp     short skip\nat_least_8_left xchg    ax, si          <font color=#007400>; read 8 sectors this time<\/font>\nskip            push    si              <font color=#007400>; number of remaining sectors<\/font>\n                push    ax              <font color=#007400>; number of sectors to read this time<\/font>\n                jmp     read_loop       <font color=#007400>; next read<\/font>\ndone            jmp     far [cs:os_offset]<font color=#007400>; jump to IBMBIO.COM<\/font>\n\ndisk_error      mov     si, FAILURE     <font color=#007400>; string to print<\/font>\n                mov     ax, rom_basic   <font color=#007400>; put return address of \"int 18\" code<\/font>\n                push    ax              <font color=#007400>; onto stack<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n<font color=#007400>; print zero-terminated string pointed to by DS:SI<\/font>\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nprint           xor     bh, bh          <font color=#007400>; XXX unnecessary<\/font>\nprint_loop      lodsb\n                and     al, <font color=#1c00cf>0x7F<\/font>        <font color=#007400>; clear bit 7 XXX why is it set?<\/font>\n                jz      ret0            <font color=#007400>; zero-termination<\/font>\n                push    si\n                mov     ah, <font color=#1c00cf>0x0E<\/font>\n                mov     bx, <font color=#1c00cf>7<\/font>           <font color=#007400>; light grey, text page 0<\/font>\n                int     <font color=#1c00cf>0x10<\/font>            <font color=#007400>; write character<\/font>\n                pop     si\n                jmp     print_loop\nret0            retn\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n<font color=#007400>; test for IBMBIO.COM and IBMDOS.COM in the first two directory entries<\/font>\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\ncheck_sys_files mov     bx, <font color=#1c00cf>0<\/font>           <font color=#007400>; read to address 0 in the DOS segment<\/font>\n                mov     cx, <font color=#1c00cf>4<\/font>           <font color=#007400>; track 0, sector 4<\/font>\n                mov     ax, <font color=#1c00cf>0x0201<\/font>\n                int     <font color=#1c00cf>0x13<\/font>            <font color=#007400>; read 1 sector<\/font>\n                push    ds\n                jc      non_system_disk <font color=#007400>; error case<\/font>\n                mov     ax, cs\n                mov     ds, ax          <font color=#007400>; DS := CS<\/font>\n                mov     di, <font color=#1c00cf>0<\/font>\n                mov     cx, <font color=#1c00cf>11<\/font>          <font color=#007400>; convert 11 bytes of first two<\/font>\nto_lower        or      byte [es:di], <font color=#1c00cf>0x20<\/font><font color=#007400>; directory entries to lowercase<\/font>\n                or      byte [es:di+<font color=#1c00cf>0x20<\/font>], <font color=#1c00cf>0x20<\/font>\n                nop                     <font color=#007400>; XXX original assembler wasted a byte<\/font>\n                inc     di\n                loop    to_lower\n                mov     di, <font color=#1c00cf>0<\/font>           <font color=#007400>; first entry<\/font>\n                mov     si, IBMBIO_COM\n                mov     cx, <font color=#1c00cf>11<\/font>\n                cld\n                rep cmpsb               <font color=#007400>; compare first entry with IBMBIO.COM<\/font>\n                jnz     non_system_disk\n                mov     di, <font color=#1c00cf>0x20<\/font>        <font color=#007400>; second entry<\/font>\n                mov     si, IBMDOS_COM\n                mov     cx, <font color=#1c00cf>11<\/font>\n                rep cmpsb               <font color=#007400>; compare second entry with IBMDOS.COM<\/font>\n                jnz     non_system_disk\n                pop     ds\n                retn                    <font color=#007400>; return with carry clear<\/font>\nnon_system_disk mov     si, NON_SYSTEM_DISK\n                call    print\n                mov     ah, <font color=#1c00cf>0<\/font>\n                int     <font color=#1c00cf>0x16<\/font>            <font color=#007400>; wait for key<\/font>\n                pop     ds\n                stc<\/font>\n                retn                    <font color=#007400>; return with carry set<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nNON_SYSTEM_DISK db <font color=#1c00cf>13<\/font>,<font color=#1c00cf>10<\/font>\n                db <font color=#c41a16>\"Non-System disk or disk erro\"<\/font>,<font color=#1c00cf>'r'<\/font>+<\/font><font color=#1c00cf>0x80<\/font><\/font>\n                db <font color=#1c00cf>13<\/font>,<font color=#1c00cf>10<\/font>\n                db <font color=#c41a16>\"Replace and strike any key when read\"<\/font>,<font color=#1c00cf>'y'<\/font>+<\/font><font color=#1c00cf>0x80<\/font>\n                db  <font color=#1c00cf>13<\/font>,<font color=#1c00cf>10<\/font>,<font color=#1c00cf>0<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nrom_basic       int     <font color=#1c00cf>0x18<\/font>                <font color=#007400>; ROM BASIC<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nFAILURE         db <font color=#1c00cf>13<\/font>,<font color=#1c00cf>10<\/font>\n                db <font color=#c41a16>\"Disk Boot failur\"<\/font>,<font color=#1c00cf>'e'<\/font>+<font color=#1c00cf>0x80<\/font>\n                db <font color=#1c00cf>13<\/font>,<font color=#1c00cf>10<\/font>,<font color=#1c00cf>0<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\nadd_si_sectors  push    ax              <font color=#007400>; bx += si*512<\/font>\n                push    dx\n                mov     ax, si\n                mov     di, <font color=#1c00cf>512<\/font>\n                mul     di\n                add     bx, ax\n                pop     dx\n                pop     ax\n                retn\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\n                db <font color=#c41a16>\"Robert O'Rear \"<\/font>\n\nIBMBIO_COM      db <font color=#c41a16>\"ibmbio  com\"<\/font>\n                db <font color=#1c00cf>0xB0<\/font>                 <font color=#007400>; XXX unused<\/font>\nIBMDOS_COM      db <font color=#c41a16>\"ibmdos  com\"<\/font>\n                db <font color=#1c00cf>0xB0<\/font>, <font color=#1c00cf>0xC9<\/font>           <font color=#007400>; XXX unused<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n\n                times <font color=#1c00cf>512<\/font>-($-$$) db <font color=#1c00cf>0<\/font>\n\n<font color=#007400>;-----------------------------------------------------------------------------<\/font>\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Update: The source is available at github.com\/mist64\/msdos1 The bootsector of DOS 1.0 is celebrating its 28th birthday today (it contains the timestamp &#8220;7-May-81&#8221;), so let&#8217;s look at it more closely. Here it is: 00000000 eb 2f 14 00 00 00 60 00 20 37 2d 4d 61 79 2d 38 |&#8230;&#8230;.. 7-May-8| 00000010 31 00 &#8230; <a title=\"Reverse-Engineering DOS 1.0 &#8211; Part 1: The Boot Sector\" class=\"read-more\" href=\"https:\/\/www.pagetable.com\/?p=165\" aria-label=\"Read more about Reverse-Engineering DOS 1.0 &#8211; Part 1: The Boot Sector\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,11,16,38],"tags":[],"class_list":["post-165","post","type-post","status-publish","format-standard","hentry","category-archeology","category-dos","category-github","category-x86"],"_links":{"self":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=165"}],"version-history":[{"count":0,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=\/wp\/v2\/posts\/165\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pagetable.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}