; Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
;
; @APPLE_LICENSE_HEADER_START@
; 
; Portions Copyright (c) 2002 Apple Computer, Inc.  All Rights
; Reserved.  This file contains Original Code and/or Modifications of
; Original Code as defined in and that are subject to the Apple Public
; Source License Version 1.2 (the "License").  You may not use this file
; except in compliance with the License.  Please obtain a copy of the
; License at http://www.apple.com/publicsource and read it before using
; this file.
; 
; The Original Code and all software distributed under the License are
; distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
; License for the specific language governing rights and limitations
; under the License.
; 
; @APPLE_LICENSE_HEADER_END@
;

kStackAddr	EQU  0xFFF0
	
		code16
		ORG 0x7c00

		SEGMENT .text
	
boot		equ $

_start:		cli
		jmp 0:start
		times 8-($-$$) nop	; Ensure table is at offset 8

		; El Torito boot information table, filled in by the
		; mkisofs -boot-info-table option
bi_pvd:		dd 0			; LBA of primary volume descriptor
bi_file:	dd 0			; LBA of boot file
bi_length:	dd 0			; Length of boot file
bi_csum:	dd 0			; Checksum of boot file
bi_reserved:	times 10 dd 0		; Reserved
	


start:
	xor ax, ax
	mov ss, ax
	mov sp, kStackAddr
	sti
	cld
	mov ds, ax
	mov es, ax
	mov [biosdrive], dl
	
	mov si, header_str
	call print_string

	mov si, drive_str	; print drive number
	call print_string
	mov al, dl
	call print_hex
	mov si, crnl_str
	call print_string
	
test1:				; Test 1: El Torito status call
	mov si, test1_str
	call print_string
	
	mov ax, 0x4b01
	mov al, 0x01
	;; dl already contains drive number
	mov esi, spec
	int 0x13

	jnc test1a		; CF clear?

test1_fail:
	mov si, test1_fail1_str
	call print_string
	jmp short test1_end
	
test1a:
	cmp [spec.drive], dl	; drive in spec packet matches?
	jne test1a_fail
	mov si, pass_str
	call print_string
	jmp short test1_end
	
test1a_fail:	
	mov si, test1_fail2_str
	call print_string

test1_end:	
	mov si, crnl_str
	call print_string
	

test2:				; Check for EBIOS support
	mov si, test2_str
	call print_string

	mov cx, 0
	mov ah, 0x41
	mov bx, 0x55aa
	mov dl, [biosdrive]
	int 0x13

	jnc test2a		; CF clear?

test2_fail:
	mov si, test2_fail1_str
	call print_string
	jmp short test2_end

test2a:
	cmp bx, 0xaa55
	je test2b

test2a_fail:
	mov si, test2_fail2_str
	call print_string
	jmp short test2_end

test2b:
	mov si, test2_vers_str	; print EDD version
	call print_string
	push cx
	mov al, ah
	call print_hex
	mov si, test2_flag_str	; print EDD flags
	call print_string
	mov al, cl
	call print_hex
	mov al, ' '
	call putc
	pop cx
	and cl, 0x01		; EDD drive access?
	jnz test2_pass

test2b_fail:
	mov si, test2_fail3_str
	call print_string
	jmp short test2_end

test2_pass
	mov si, pass_str
	call print_string
	
test2_end:	
	mov si, crnl_str
	call print_string

test3:				; Disk geometry
	mov si, test3_str
	call print_string	

	mov ah, 0x48
	mov dl, [biosdrive]
	mov si, disk_params
	int 0x13

	jnc test3a

test3_fail:
	mov si, test3_fail1_str
	call print_string
	jmp test3_end

test3a:
	cmp word [disk_params.nbps], 0x0800
	je test3_pass

test3a_fail:
	mov al, [disk_params.nbps+1]
	call print_hex
	mov al, [disk_params.nbps]
	call print_hex
	mov al, ' '
	call putc
	mov si, test3_fail2_str
	call print_string
	jmp test3_end
	
test3_pass:
	mov si, pass_str
	call print_string
	
test3_end:
	mov si, crnl_str
	call print_string
	
	
finished:	
	mov si, finished_str
	call print_string
	
halt:	hlt
	jmp short halt

	

	;; ----- Helper functions -----

	;; putc(ch)
	;; character in AL
	;; clobbers AX, BX
putc:	mov bx, 0x000f
	mov ah, 0x0e
	int 0x10
	ret

	;; getc()
	;; clobbers AH
	;; returns character in AL
getc:	mov ah, 0
	int 0x16
	ret

;--------------------------------------------------------------------------
; Write the byte value to the console in hex.
;
; Arguments:
;   AL = Value to be displayed in hex.
;
print_hex:
    push    ax
    ror     al, 4
    call    print_nibble            ; display upper nibble
    pop     ax
    call    print_nibble            ; display lower nibble
    ret

print_nibble:
    and     al, 0x0f
    add     al, '0'
    cmp     al, '9'
    jna     .print_ascii
    add     al, 'A' - '9' - 1
.print_ascii:
    call    putc
    ret

;--------------------------------------------------------------------------
; Write a string to the console.
;
; Arguments:
;   DS:SI   pointer to a NULL terminated string.
;
; Clobber list:
;   none
;
print_string:
    pushad
    mov     bx, 1                   ; BH=0, BL=1 (blue)
.loop
    lodsb                           ; load a byte from DS:SI into AL
    cmp     al, 0                   ; Is it a NULL?
    je      .exit                   ; yes, all done
    mov     ah, 0xE                 ; INT10 Func 0xE
    int     0x10                    ; display byte in tty mode
    jmp     short .loop
.exit
    popad
    ret


	SEGMENT .data
	
	;; Strings

header_str:	db "BIOS test v0.3", 10,13, 0
finished_str:	db "Tests completed.", 10,13,0
drive_str:	db "Boot drive: ", 0
pass_str:	db "pass", 0
fail_str:	db "FAIL", 0
crnl_str:	db 10,13, 0
test1_str:	db "Test 1: El Torito status: ", 0
test1_fail1_str:	db "FAIL (CF=1)", 0
test1_fail2_str:	db "FAIL (spec drive)", 0
test2_str:	db "Test 2: EBIOS check: ", 0
test2_vers_str:	db "vers. ", 0
test2_flag_str:	db " flags ", 0
test2_fail1_str:	db "FAIL (CF=1)", 0
test2_fail2_str:	db "FAIL (BX != AA55)", 0
test2_fail3_str:	db "FAIL (CL & 1 == 0)", 0
test3_str:	db "Test 3: Geometry check: ", 0
test3_fail1_str:	db "FAIL (CF=1)", 0
test3_fail2_str:	db "FAIL (nbps != 0x200)", 0
	
	;; Other variables
	
biosdrive:	db 0

	;; El Torito spec packet
spec:	
.size:		db 0x13
.type:		db 0
.drive:		db 0
.index:		db 0
.lba:		dd 0
.spec:		dw 0
.userseg:	dw 0
.loadseg:	dw 0
.seccnt:	dw 0
.cylcnt:	db 0
.ccl:		db 0
.hdcnt:		db 0

	;; Disk parameter packet
disk_params:	
.size:		dw 66
.flags:		dw 0
.cyls:		dd 0
.heads:		dd 0
.spt:		dd 0
.sectors:	dd 0,0
.nbps:		dw 0
.dpte_offset:	dw 0
.dpte_segment:	dw 0
.key:		dw 0
.ignored:	times 34 db 0

	
