Advertisement
a4lg

FAT32 boot sector implementation test (fix 2)

Apr 6th, 2012
465
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
ASM (NASM) 11.42 KB | None
  1. ; FAT32 boot sector implementation test (fix and optimization 2)
  2. ; Note:
  3. ;  * Fixed all bugs reported by @hdk_2
  4. ;  * I changed the code so much which might introduce new bugs.
  5. cpu  8086
  6. bits 16
  7. org  0x7c00
  8.  
  9. _start:
  10.     jmp short start
  11.     nop
  12.  
  13. _bpb_oem_name:
  14.     db "SMALLOS"
  15.     times 8-($-_bpb_oem_name) db " "
  16. _bpb_numbytes_sec:
  17.     dw 0x0200
  18. _bpb_numsec_clus:
  19.     db 0x01
  20. _bpb_numsec_rsvd:
  21.     dw 0x0020
  22. _bpb_numfat:
  23.     db 0x02
  24. _bpb_numroot:
  25.     dw 0x0000
  26. _bpb_numsec_total16:
  27.     dw 0x0000
  28. _bpb_media_descriptor:
  29.     db 0xf8
  30. _bpb_numsec_fat16:
  31.     dw 0x0000
  32. _bpb_numsec_track:
  33.     dw 0x0020
  34. _bpb_numheads:
  35.     dw 0x0040
  36. _bpb_numsec_hidden:
  37.     dd 0x00000000
  38. _bpb_numsec_total32:
  39.     dd 0x00010000
  40. _bpb_numsec_fat32:
  41.     dd 0x000001f8
  42. _bpb_mirror_flags:
  43.     dw 0x0000
  44. _bpb_fat32_version:
  45.     db 0, 0
  46. _bpb_offclus_root:
  47.     dd 0x00000002
  48. _bpb_offsec_fsinfo:
  49.     dw 0x0001
  50. _bpb_offsec_backup:
  51.     dw 0x0006
  52. _bpb_fat32_reserved:
  53.     times 12 db 0
  54. _bpb_physical_drive:
  55.     db 0x00
  56. _bpb_fat16_reserved:
  57.     db 0x00
  58. _bpb_ext_boot_sign:
  59.     db 0x29
  60. _bpb_volume_id:
  61.     dd 0x12345678
  62. _bpb_volume_label:
  63.     db "SMALLOS"
  64.     times 11-($-_bpb_volume_label) db " "
  65. _bpb_fs_type:
  66.     db "FAT32"
  67.     times 8-($-_bpb_fs_type) db " "
  68.  
  69. %define STK_BASE 0x7be2
  70. %define REL_BASE 0x7c0b
  71.  
  72. %define ADRH_INIT   0x10
  73. %define ADRH_LIMIT  0x50
  74. %define ADRH_INFO   0x60
  75. %define ADDR_INIT   ADRH_INIT * 0x100
  76. %define ADDR_LIMIT  ADRH_LIMIT * 0x100
  77. %define ADDR_INFO   ADRH_INFO * 0x100
  78.  
  79. %define tmp_dx          0x7be0
  80. %define tmp_offsec_fat  0x7bdc
  81. %define tmp_offsec_data 0x7bd8
  82. %define tmp_ext13h_buf  0x7bf0
  83. %define bpb_oem_name            0x7c03
  84. %define bpb_numbytes_sec        0x7c0b
  85. %define bpb_numsec_clus         0x7c0d
  86. %define bpb_numsec_rsvd         0x7c0e
  87. %define bpb_numfat              0x7c10
  88. %define bpb_numroot             0x7c11
  89. %define bpb_numsec_total16      0x7c13
  90. %define bpb_media_descriptor    0x7c15
  91. %define bpb_numsec_fat16        0x7c16
  92. %define bpb_numsec_track        0x7c18
  93. %define bpb_numheads            0x7c1a
  94. %define bpb_numsec_hidden       0x7c1c
  95. %define bpb_numsec_total32      0x7c20
  96. %define bpb_numsec_fat32        0x7c24
  97. %define bpb_mirror_flags        0x7c28
  98. %define bpb_fat32_version       0x7c2a
  99. %define bpb_offclus_root        0x7c2c
  100. %define bpb_offsec_fsinfo       0x7c30
  101. %define bpb_offsec_backup       0x7c32
  102. %define bpb_fat32_reserved      0x7c34
  103. %define bpb_physical_drive      0x7c40
  104. %define bpb_fat16_reserved      0x7c41
  105. %define bpb_ext_boot_sign       0x7c42
  106. %define bpb_volume_id           0x7c43
  107. %define bpb_volume_label        0x7c47
  108. %define bpb_fs_type             0x7c52
  109.  
  110. %define rel(x) di-REL_BASE+x
  111. %define rel_bpb(x) rel(bpb_%+x)
  112. %define rel_tmp(x) rel(tmp_%+x)
  113.  
  114. start:
  115.     ; DL == drive
  116.     ; IF := 0
  117.     cli
  118.     ; AX:=DS:=ES:=SS:=0
  119.     xor  ax, ax
  120.     mov  ds, ax
  121.     mov  es, ax
  122.     mov  ss, ax
  123.     ; SP := STK_BASE
  124.     ; DI := REL_BASE
  125.     mov  sp, STK_BASE
  126.     mov  di, REL_BASE
  127.     push dx ; tmp_dx
  128. disk_reset:
  129.     ; BIOS CALL: RESET DISK
  130.     ; AH == 0
  131.     ; DL == drive
  132.     ; CF := error
  133.     int  0x13
  134.     jc   short _err_boot_2
  135. disk_check_ext13h:
  136.     mov  ah, 0x41
  137.     mov  bx, 0x55aa
  138.     ; BIOS CALL: CHECK EXTENDED INT13H
  139.     ; AH == 0x41
  140.     ; BX == 0x55AA
  141.     ; if EXTENDED INT13H is supported:
  142.     ;    CF := 0
  143.     ;    BX := 0xAA55
  144.     ;    CX := (other flags) | 1
  145.     int  0x13
  146.     jc   short fs_calc_geom
  147.     sub  bx, 0xaa55
  148.     jne  short fs_calc_geom
  149.     shr  cx, 1
  150.     jnc  short fs_calc_geom
  151.     ; BL == 0
  152.     ; SMI1 -> SMC1
  153.     mov  byte[_read_disk_branch+1], bl
  154. fs_calc_geom:
  155.     ; SI:BP := dword(numsec_hidden) + word(numsec_rsvd)
  156.     ;       == dword(offsec_fat)
  157.     mov  bp, [rel_bpb(numsec_hidden)]
  158.     mov  si, [rel_bpb(numsec_hidden)+2]
  159.     add  bp, [rel_bpb(numsec_rsvd)]
  160.     adc  si, byte 0
  161.     push si ; tmp_offsec_fat+2
  162.     push bp ; tmp_offsec_fat
  163.     ; [numfat] := 0
  164.     ; SI:BP    := dword(offsec_data)
  165.     _fs_calc_geom_fat:
  166.         add  bp, [rel_bpb(numsec_fat32)]
  167.         adc  si, [rel_bpb(numsec_fat32)+2]
  168.         dec  byte[rel_bpb(numfat)]
  169.         jnz  _fs_calc_geom_fat
  170.     push si ; tmp_offsec_data+2
  171.     push bp ; tmp_offsec_data
  172.     ; BX := ADDR_INIT
  173.     mov  bx, ADDR_INIT
  174. fs_traverse_fat_init:
  175.     ; AX:SI := dword(offclus_root)
  176.     mov  ax, [rel_bpb(offclus_root)+2]
  177.     mov  si, [rel_bpb(offclus_root)]
  178. fs_traverse_fat:
  179.     ; AX:SI == dword(cluster)
  180.     ; AX:SI := dword(cluster) - 2
  181.     push ax
  182.     push si
  183.     xor  cx, cx
  184.     sub  si, byte 2
  185.     sbb  ax, cx
  186.     _err_boot_2:
  187.         jc   short err_boot
  188.     ; CX == 0
  189.     ; CX := word(numsec_clus)
  190.     mov  cl, [rel_bpb(numsec_clus)]
  191.     ; AX == word(cluster_hi)
  192.     ; AX := word(cluster_hi) * word(numsec_clus)
  193.     mul  cx
  194.     ; AX := word(cluster_lo)
  195.     ; SI := word(cluster_hi) * word(numsec_clus)
  196.     xchg ax, si
  197.     ; DX:AX := word(cluster_lo) * word(numsec_clus)
  198.     mul  cx
  199.     ; SI    == word(cluster_hi) * word(numsec_clus)
  200.     ; DX:AX := dword(offsec_clus_read)
  201.     add  dx, si
  202.     add  ax, [rel_tmp(offsec_data)]
  203.     adc  dx, [rel_tmp(offsec_data)+2]
  204.     ; CX == word(numsec_clus)
  205.     fs_traverse_fat_1:
  206.         ; DX:AX++
  207.         call read_disk
  208.         ; SMC2: e8 xxxx (boot_find_file) -> be xxxx (MOV si, xxxx)
  209.         _fs_traverse_fat_call:
  210.             call boot_find_file
  211.         ; BL == 0
  212.         ; boot if BX >= ADDR_LIMIT
  213.         cmp  bh, ADRH_LIMIT
  214.         jae  short boot
  215.         ; Loop (CX--)
  216.         loop fs_traverse_fat_1
  217.     ; AX:CX := dword(cluster)
  218.     pop  cx
  219.     pop  ax
  220.     push bx
  221.     ; AX:CX := dword(cluster) * 4
  222.     add  cx, cx
  223.     adc  ax, ax
  224.     add  cx, cx
  225.     adc  ax, ax
  226.     ; BP    := word(numbytes_sec)
  227.     ; DX    := word(offbytes_clus_fat)
  228.     ; CX:AX := dword(offsec_clus_fat)
  229.     mov  bp, [rel_bpb(numbytes_sec)]
  230.     call div32_short
  231.     ; DX:AX := dword(offsec_clus_fat)
  232.     ; SI    := word(offbytes_clus_fat)
  233.     ; BL    == 0
  234.     ; BX    := ADDR_INFO -> ADDR_INFO+sec -> ADDR_INFO
  235.     xchg dx, cx
  236.     mov  bh, ADRH_INFO
  237.     add  ax, [rel_tmp(offsec_fat)]
  238.     adc  dx, [rel_tmp(offsec_fat)+2]
  239.     call read_disk
  240.     mov  si, cx
  241.     sub  bx, [rel_bpb(numbytes_sec)]
  242.     ; [BX+SI] == dword(next_clus)
  243.     ; AX:SI   := dword(next_clus)
  244.     ; BP      := 0x0FFF
  245.     mov  ax, [bx+si+2]
  246.     mov  si, [bx+si]
  247.     pop  bx
  248.     mov  bp, 0x0fff
  249.     and  ax, bp
  250.     ; Normal cluster if AX != 0x0FFF
  251.     cmp  ax, bp
  252.     jne  short fs_traverse_fat
  253.     ; Check terminator
  254.     cmp  si, byte -9
  255.     _fs_traverse_fat_1:
  256.         jna  short fs_traverse_fat
  257.     ; SMC3: eb xx (err_boot) -> eb 00
  258.     _fs_traverse_fat_branch:
  259.         jmp  short err_boot
  260. boot:
  261.     ; DL := drive
  262.     ; DH := file system type
  263.     ; jump to INIT_ADDR
  264.     mov  dl, [rel_tmp(dx)]
  265.     mov  dh, 3
  266.     jmp  near ADDR_INIT
  267.  
  268. ; SUBROUTINE
  269. err_boot:
  270.     mov  si, boot_error_msg
  271.     mov  cx, boot_error_msg_end-boot_error_msg
  272.     _err_boot_loop:
  273.         ; DF := 0
  274.         ; AL := char
  275.         cld
  276.         lodsb
  277.         mov  ah, 0x0e
  278.         mov  bx, 0x0007
  279.         int  0x10
  280.         loop _err_boot_loop
  281.     xor  ax, ax
  282.     ; BIOS CALL: WAIT FOR KEY
  283.     ; AH == 0
  284.     int  0x16
  285.     ; BIOS CALL: REBOOT
  286.     int  0x19
  287.     ; just padding :)
  288. err_boot_final:
  289.     hlt
  290.     jmp  short err_boot_final
  291.  
  292. ; BOOT PROCEDURE
  293. boot_found_file:
  294.     ; SI    == directory entry
  295.     ; AX:SI := dword(file_clus)
  296.     mov  ax, [si+0x14]
  297.     mov  si, [si+0x1a]
  298.     ; CH == 0
  299.     ; ZF := 1
  300.     ; SMI2 -> SMC2
  301.     ; SMI3 -> SMC3
  302.     mov  byte[_fs_traverse_fat_call], 0xbe
  303.     and  byte[_fs_traverse_fat_branch+1], ch
  304.     ; Back to FAT32 traversal
  305.     jmp  short _fs_traverse_fat_1
  306.  
  307. ; REGISTERS PRESERVED
  308. ;  CX
  309. ; REGISTERS TO MODIFY
  310. ;  AX, DX, BX
  311. ; REGISTERS TO DESTROY
  312. ;  SI, BP
  313. ; PARAMETERS
  314. ;  BX:    BUFFER
  315. ;  DX:AX: LBA
  316. ; RESULTS
  317. ;  BX:    address of empty space
  318. ;  DX:AX: LBA+1
  319. read_disk:
  320.     _read_disk_init:
  321.         push ax
  322.         push cx
  323.         push dx
  324.     _read_disk_branch:
  325.         ; SMC1: eb xx (_read_disk_noext) -> eb 00
  326.         jmp short _read_disk_noext
  327.     _read_disk_ext:
  328.         cld
  329.         ; DI == REL_BASE
  330.         ; SI := ext13h_buf
  331.         ; DI := ext13h_buf
  332.         lea  si, [rel_tmp(ext13h_buf)]
  333.         push di
  334.         mov  di, si
  335.         ; AX == LBA_LO
  336.         ; AX := 0x0010
  337.         push ax
  338.         mov  ax, 0x0010
  339.         stosw
  340.         ; AH == 0
  341.         ; AX := 0x0001
  342.         mov  al, 0x01
  343.         stosw
  344.         ; AX := BUFFER
  345.         mov  ax, bx
  346.         stosw
  347.         ; AX := 0
  348.         xor  ax, ax
  349.         stosw
  350.         ; AX := LBA_LO
  351.         pop  ax
  352.         stosw
  353.         ; AX := LBA_HI
  354.         ; DX := LBA_LO
  355.         xchg ax, dx
  356.         stosw
  357.         ; AX := 0
  358.         xor  ax, ax
  359.         stosw
  360.         stosw
  361.         ; DI := REL_BASE
  362.         ; EXTENDED READ DISK
  363.         ; AH := 0x42
  364.         ; AL == 0 (may be used by some BIOS)
  365.         ; DL := byte(drive)
  366.         ; SI := ext13h_buf
  367.         ; Contents of ext13h_buf(si):
  368.         ; +00: 0x0010 (size of ext13h_buf)
  369.         ; +02: 0x0001 (sectors to read)
  370.         ; +04: BUFFER
  371.         ; +06: 0x0000 (segment 0)
  372.         ; +08: LBA_LO
  373.         ; +0a: LBA_HI
  374.         ; +0c: 0x0000
  375.         ; +0e: 0x0000
  376.         mov  ah, 0x42
  377.         pop  di
  378.     _read_disk_perform:
  379.         mov  dl, [rel_tmp(dx)]
  380.         int  0x13
  381.         ; CF == error
  382.         jc   short err_boot
  383.     _read_disk_fini:
  384.         pop  dx
  385.         pop  cx
  386.         pop  ax
  387.         ; BX += word(numbytes_sec)
  388.         ; DX:AX++
  389.         add  bx, [rel_bpb(numbytes_sec)]
  390.         inc  ax
  391.         jnz  _read_disk_fini_1
  392.         inc  dx
  393.     _read_disk_fini_1:
  394.         ret
  395.  
  396. ; BOOT PROCEDURE
  397. ; REGISTERS PRESERVED
  398. ;  CX
  399. ; REGISTERS TO DESTROY
  400. ;  SI
  401. ; PARAMETERS
  402. ;  BX: INIT_ADDR + bytes of sector
  403. ; RESULTS
  404. ;  (jump to boot_find_file_1)
  405. ;  SI: found directory entry
  406. boot_find_file:
  407.     mov  bp, bx
  408.     ; BX := SI := INIT_ADDR
  409.     sub  bx, [rel_bpb(numbytes_sec)]
  410.     mov  si, bx
  411.     boot_find_file_1:
  412.         ; SI        == directory entry
  413.         ; +00-0A: FILE NAME
  414.         ; +0B-0B: FILE ATTRIBUTES
  415.         ; +0D-0C: METADATA?
  416.         ; +0D-0D: CREATE_TIME_MS
  417.         ; +0E-0F: CREATE_TIME
  418.         ; +10-11: CREATE_DATE
  419.         ; +12-13: ACCESS_DATE
  420.         ; +14-15: CLUSTER_HI
  421.         ; +16-17: MODIFY_TIME
  422.         ; +18-19: MODIFY_DATE
  423.         ; +1A-1B: CLUSTER_LO
  424.         ; +1C-1F: FILE_SIZE
  425.         ; [SI+0] == file name (first byte)
  426.         ;           no subsequent entries if 0
  427.         ; [SI+0x0B] == file attributes
  428.         ; File attributes to reject:
  429.         ;  0x08: Volume Label (or VFAT File Name)
  430.         ;  0x10: Subdirectory
  431.         ;  0x40: Device
  432.         cmp  byte[si], ch
  433.         je   short err_boot
  434.         test byte[si+0x0b], 0x58
  435.         jnz  short boot_find_file_next
  436.         boot_find_file_cmp:
  437.             ; CX == directory table loop remaining
  438.             ; CX := 11 (length of file name)
  439.             ; SI == directory entry
  440.             ; DI := boot_file
  441.             ; DF := 0
  442.             push cx
  443.             push si
  444.             push di
  445.             mov  cl, 0x0b
  446.             mov  di, boot_file
  447.             cld
  448.             repe cmpsb
  449.             pop  di
  450.             pop  si
  451.             pop  cx
  452.             ; found directory entry if file names are equal
  453.             je   short boot_found_file
  454.         boot_find_file_next:
  455.             ; SI := next directory entry
  456.             add  si, byte 0x20
  457.             cmp  si, bp
  458.             jb   boot_find_file_1
  459.     ret
  460.  
  461. ; PART of read_disk
  462. read_disk_chunk_2:
  463.     _read_disk_noext:
  464.         ; BP    := word(numsec_track)
  465.         ; CX:AX := dword(LBA)
  466.         mov  bp, [rel_bpb(numsec_track)]
  467.         mov  cx, dx
  468.         ; CX:AX := dword(LBA) / word(numsec_track)
  469.         ;       == dword(HEAD_CYLINDER)
  470.         ; DX    := dword(LBA) % word(numsec_track)
  471.         call div32
  472.         ; SI := DX == word(SECTOR)
  473.         inc  dx
  474.         mov  si, dx
  475.         and  si, byte 0x3f
  476.         ; BP    := word(numheads)
  477.         ; CX:AX := dword(HEAD_CYLINDER) / word(numheads)
  478.         ;       == dword(CYLINDER)
  479.         ; DX    := dword(HEAD_CYLINDER) % word(numheads)
  480.         ;       == word(HEAD)
  481.         mov  bp, [rel_bpb(numheads)]
  482.         call div32
  483.         ; [INT 13h's CYLINDER is a word value (discard CX)]
  484.         ; CL := 6
  485.         ; AL == byte(CYLINDER_LO)
  486.         ; AH := byte(CYLINDER_HI) << 6
  487.         mov  cl, 6
  488.         shl  ah, cl
  489.         ; AL := byte(CYLINDER_HI) << 6 | byte(SECTOR)
  490.         ; AH := byte(CYLINDER_LO)
  491.         xchg al, ah
  492.         or   ax, si
  493.         ; AX == word(CYLINDER/SECTOR)
  494.         ; CX := word(CYLINDER/SECTOR)
  495.         xchg ax, cx
  496.         ; DL == byte(HEAD)
  497.         ; DH := byte(HEAD)
  498.         mov  dh, dl
  499.         ; READ DISK
  500.         ; AX := 0x0201 (0x02: read, 0x01: sectors to read)
  501.         ; DL := byte(drive)
  502.         ; DH == byte(HEAD)
  503.         ; CX == word(CYLINDER/SECTOR)
  504.         ; BX == BUFFER
  505.         mov  ax, 0x0201
  506.         jmp  short _read_disk_perform
  507.  
  508. ; REGISTER TO MODIFY
  509. ;  AX CX DX
  510. ; PARAMETERS
  511. ;  CX:AX: DIVIDEND
  512. ;  BP:    DIVISOR
  513. ; RESULTS
  514. ;  CX:AX: DIVIDEND / DIVISOR
  515. ;  DX:    DIVIDEND % DIVISOR
  516. div32:
  517.     xchg ax, cx
  518. div32_short:
  519.     xor  dx, dx
  520.     div  bp
  521.     xchg ax, cx
  522.     div  bp
  523.     ret
  524.  
  525. boot_file:
  526.     db  'KERNEL  BIN'
  527. boot_error_msg:
  528.     db  'No System Disk.',0x0d,0x0a
  529.     db  'Press any key to reboot.',0x0d,0x0a
  530. boot_error_msg_end:
  531.  
  532. _end:
  533.     times 512-2-($-$$) db 0x00
  534.     dw  0xaa55
Advertisement
RAW Paste Data Copied
Advertisement