;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2014-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Kolibri OS support loader for GRUB
;
; Copyright (C) Alex Nogueira Teixeira
; Copyright (C) Diamond
; Copyright (C) Dmitry Kartashov aka shurf
; Copyright (C) Serge
;
; Distributed under GPL, see file COPYING for details
;
; Version 1.0

lf              =     0x0A
cr              =     0x0D

use32


org 0x100000

mboot:
  dd  0x1BADB002
  dd  0x00010003
  dd  -(0x1BADB002 + 0x00010003)
  dd  mboot
  dd  0x100000
  dd  __edata
  dd  __end
  dd  __start

align 16
__start:

virtual at ebp+3
.BS_OEMName      rb 8
.BPB_BytsPerSec  rw 1           ; bytes per sector
.BPB_SecPerClus  rb 1           ; sectors per cluster
.BPB_RsvdSecCnt  rw 1           ; number of reserver sectors
.BPB_NumFATs     rb 1           ; count of FAT data structures
.BPB_RootEntCnt  rw 1           ; count of 32-byte dir. entries (224*32 = 14 sectors)
.BPB_TotSec16    rw 1           ; count of sectors on the volume (2880 for 1.44 mbytes disk)
.BPB_Media       rb 1           ; f0 - used for removable media
.BPB_FATSz16     rw 1           ; count of sectors by one copy of FAT
.BPB_SecPerTrk   rw 1           ; sectors per track
.BPB_NumHeads    rw 1           ; number of heads
.BPB_HiddSec     rd 1           ; count of hidden sectors
.BPB_TotSec32    rd 1           ; count of sectors on the volume (if > 65535)
end virtual

        cld
        mov     esi, mboot
        mov     edi, 0x80000
        mov     ecx, 624/4                      ;magic value
        rep movsd
        jmp     .check_mbi

org $-0x80000
align 4
.check_mbi:
        cmp     eax, 0x2BADB002
        mov     esi, sz_invboot
        jne     .panic

        bt      dword [ebx], 3
        mov     esi, sz_nomods
        jnc     .panic

        mov     edx, [ebx+20]                   ;mods_count
        mov     edi, [ebx+24]                   ;mods_addr
        cmp     edx, 1
        mov     esi, sz_nomods
        jne     .panic

.scan_mod:
        mov     ebp, [edi]                      ;image start
        mov     ecx, [edi+4]                    ;image end
        sub     ecx, ebp                        ;image size
        cmp     ecx, 512*18*80*2                ;1.44 floppy
        mov     esi, sz_image
        jne     .panic

        mov     [_image_start], ebp
        mov     [_image_size], ecx

; calculate some disk parameters
; - beginning sector of RootDir

        movzx   eax, word [.BPB_FATSz16]
        movzx   ecx, byte [.BPB_NumFATs]
        mul     ecx
        add     ax, [.BPB_RsvdSecCnt]
        mov     [FirstRootDirSecNum], eax
        mov     esi, eax

; - count of sectors in RootDir
        movzx   ebx, word [.BPB_BytsPerSec]
        mov     cl, 5                           ; divide ax by 32
        shr     ebx, cl                         ; bx = directory entries per sector
        movzx   eax, word [.BPB_RootEntCnt]
        xor     edx, edx
        div     ebx
        mov     [RootDirSecs], eax

        ; - data start
        add     esi, eax                        ; add beginning sector of RootDir and count sectors in RootDir
        mov     [data_start], esi

; reading root directory
; al=count root dir sectrors !!!! TODO: al, max 255 sectors !!!!

        mov     eax, [FirstRootDirSecNum]
        mul     word [.BPB_BytsPerSec]
        lea     esi, [ebp+eax]

        mov     eax, [RootDirSecs]
        mul     word [.BPB_BytsPerSec]
        add     eax, esi                        ; EAX = end of root dir. in buffer pos_read_tmp

; find kernel file in root directory

.loop_find_dir_entry:
        push    esi
        mov     ecx, 11
        mov     edi, kernel_name
        rep cmpsb                               ; compare es:si and es:di, cx bytes long
        pop     esi
        je      .found_kernel_file
        add     esi, 32                         ; next dir. entry
        cmp     esi, eax                        ; end of directory
        jb      .loop_find_dir_entry

        mov     esi, sz_kernel
        jmp     .panic

        ; === KERNEL FOUND. LOADING... ===

.found_kernel_file:

        movzx   ecx, word [esi+01ah]            ; first cluster of kernel file

        ; reading first FAT table
        movzx   eax, word [.BPB_RsvdSecCnt]     ; begin first FAT abs sector number
        mul     word [.BPB_BytsPerSec]
        lea     ebx, [ebp+eax]                  ; FAT address

;ebx = FAT
;ecx = cluster
;esi = src
;edi = dst
;ebp = image

; copy kernel file

        movzx   eax, word [.BPB_BytsPerSec]
        movsx   edx, byte [.BPB_SecPerClus]
        mul     edx
        shr     eax, 2
        mov     [cluster_size], eax

        mov     edi, 0x10000                    ;kernel base address

.copy_kernel:

        ; convert cluster number to sector number
        mov     eax, ecx                        ; data cluster to read
        sub     eax, 2
        movzx   edx, byte [.BPB_SecPerClus]
        mul     edx
        add     eax, [data_start]
        movzx   edx, word [.BPB_BytsPerSec]
        mul     edx

        lea     esi, [ebp+eax]
        mov     edx, ecx
        mov     ecx, [cluster_size]
        rep movsd
        mov     ecx, edx

        shr     edx, 1
        pushf
        add     edx, ecx                        ; di = bp * 1.5
        mov     ax, word [ebx+edx]             ; read next entry from FAT-chain
        popf
        jc      .move_4_right
        and     ax, 0fffh
        jmp     .verify_end_sector
.move_4_right:
        shr     ax, 4
.verify_end_sector:
        cmp     ax, 0ff8h                       ; last cluster
        jae     .execute_kernel
        movzx   ecx, ax
        jmp     .copy_kernel

.execute_kernel:

        mov     edi, 0x100000
        mov     esi, [_image_start]
        mov     ecx, [_image_size]
        shr     ecx, 2
        rep movsd
        xor     eax, eax
        mov     ecx, 1024
        rep stosd

        xor     ebx, ebx
        xor     ecx, ecx
        xor     edx, edx
        xor     esi, esi
        xor     edi, edi
        xor     ebp, ebp
        xor     esp, esp

        lgdt    [.tmp_gdt]
        jmp     far 0x08:.mode_16 and 0xFFFF

.panic:
        mov     ebx, sz_halt
        mov     edx, 0xb8000+160*10+2
        mov     ah, 0x07
.line:
        mov     edi, edx
.print:
        lodsb
        test    al, al
        jz      .print_next
        stosw
        jmp     .print

.print_next:
        test    ebx, ebx
        jz      ._hlt

        mov     esi, ebx
        xor     ebx, ebx
        add     edx, 160
        jmp     .line

._hlt:
        hlt
        jmp     ._hlt

align 8
.tmp_gdt: dw 15
          dd .tmp_gdt
          dw 0

.code16:  dw 0xFFFF
          dw 0
          db 8
          db 10011010b
          dw 0

use16
.mode_16:
        mov     eax, cr0
        and     eax, not 0x80000001
        mov     cr0, eax
        jmp     far 0x8000:.real_mode and 0xFFFF

.real_mode:
        xor     eax, eax
        mov     ds, ax
        mov     es, ax
        mov     ss, ax
        mov     gs, ax
        mov     fs, ax
        jmp     far 0x1000:0000


sz_invboot   db 'Invalid multiboot loader magic value',0
sz_nomods    db 'No image loaded',0
sz_image     db 'Image size invalid',0
sz_halt      db 'Halted',0

sz_kernel    db cr
kernel_name  db 'KERNEL  MNT ?',0

org $+0x80000
__edata:

align 4
_image_start        rd 1
_image_size         rd 1

FirstRootDirSecNum  rd 1
RootDirSecs         rd 1
data_start          rd 1
cluster_size        rd 1
__end: