     1                                  ; Boot sector to load up an OS kernel
     2                                  ;
     3                                  ; Copyright (C) 1999 Thomas Novelli
     4                                  ;	Retro is distributed under the terms of the GNU LGPL, version 2 or
     5                                  ;	greater. (For the text of the license, see the file COPYING.LIB)
     6                                  ;
     7                                  ; Platform: Intel x86
     8                                  ;	Thanks for the tips & examples: Linus Torvalds, John S. Fine,
     9                                  ;	M. J. Vines, Francois-Rene Rideau
    10                                  ;
    11                                  ; To do:
    12                                  ;	Eventually, load kernel from a file/object (after the persistent
    13                                  ;	storage system has stabilized)
    14                                  ;
    15                                  ;
    16                                  ; Here's how it works:
    17                                  ;
    18                                  ; BIOS: 
    19                                  ;  1. Loads Sector 1, Track 0, Head 0 to address 7C00
    20                                  ;  2. Checks the last two bytes of the bootsector, which must contain
    21                                  ;     the signature 0xAA55, or it says "Operating system not found".
    22                                  ;  3. Loads DL with:
    23                                  ;	0x00 if booted from drive A
    24                                  ;	0x80 if booted from drive C
    25                                  ;	(Note: What about bootable CD's? 0x81, 0x82, etc?)
    26                                  ;  4. Jumps to 0000:7C00
    27                                  ;
    28                                  ; Boot loader:
    29                                  ;  1. Initializes segments & stack
    30                                  ;  2. Prints a message
    31                                  ;  3. Loads the rest of the boot loader, starting at address 7E00
    32                                  ;
    33                                  ; Initialization:
    34                                  ;  1. Checks some things, like the CPU type, RAM availble, etc.
    35                                  ;  2. Starts protected mode (386+ only)
    36                                  ;
    37                                  ; Kernel:
    38                                  ;  The kernel (core of the operating system) is responsible for loading
    39                                  ;  and managing all programs/objects.
    40                                  
    41                                  ; Memory map:
    42                                  ;	0000 to 03FF	; Real mode Interrupt Vector Table
    43                                  ;	0400 to 049F	; BIOS data area
    44                                  ;	7000 to 7BFF	; Stack for boot loader
    45                                  ;	7C00 to 7DFF	; Boot sector
    46                                  ;	7E00 to ????	; Extended boot loader & OS kernel
    47                                  
    48                                  BITS 16
    49                                  
    50                                  ;Note: we could detect the boot address if that helps. CALL $+2 and POP..
    51                                  
    52                                  %define BOOTSEG		0x7C0	; BIOS puts the boot sector at address 7C00
    53                                  %define STACKSEG	0x700	; This area should be free for the stack...
    54                                  
    55                                  ;; Some debugging macros
    56                                  %macro hexp 1	;; hexp <number>
    57                                  	pusha
    58                                  	push word %1
    59                                  	mov	bp, sp
    60                                  	call	hex_print
    61                                  	call	print_nl
    62                                  	popa
    63                                  %endmacro
    64                                  
    65                                  %define hang	jmp short $
    66                                  
    67                                  
    68                                  	ORG	0x7C00
    69                                  
    70                                  boot_start:
    71 00000000 EB3C                    	jmp short start
    72 00000002 90                      	nop
    73                                  
    74                                  
    75                                  ;--------------------------------------------------------------------
    76                                  ;
    77                                  ; Data block
    78                                  ;
    79                                  data:
    80 00000003 01                      .sects	db	num_sectors	;Number of extra sectors used by boot loader
    81                                  ;.sects	db	10
    82                                  
    83 00000004 24000000                .moddir	dd	36		;Module directory (sector #)
    84 00000008 25000000                .modord	dd	37		;Module loading order (sector #)
    85 0000000C 00<rept>                times	(0x3B - ($-data))	db	0
    86                                  
    87                                  
    88                                  ;--------------------------------------------------------------------
    89                                  
    90                                  
    91                                  start:
    92 0000003E 31C0                    	xor	ax, ax		; Initialize segments
    93 00000040 8ED8                    	mov     ds, ax		;ds,es = 0
    94 00000042 8EC0                    	mov	es, ax
    95 00000044 B80007                  	mov	ax, STACKSEG
    96 00000047 8ED0                    	mov     ss, ax
    97 00000049 BC000C                  	mov     sp, 0xC00
    98                                  
    99 0000004C 8816[CE01]              	mov	[boot_drive], dl	;BIOS passes this along; save it.
   100                                  
   101                                  ; An attempt to solve Tril's problem with his CGA. It flickers for a few
   102                                  ; seconds, then winds up in 40x25 mode somehow, with "Welcome to DDR.." at
   103                                  ; the upper left.
   104                                  ;
   105                                  ;	mov	ax, 0x0003		; Set video mode 03h
   106                                  ;	int	0x10
   107                                  
   108 00000050 BD[9F01]                        mov     bp, boot_msg		; Startup message
   109 00000053 E83201                          call    print_string
   110                                  
   111                                  ; Load kernel
   112 00000056 E8B200                  	call	probe
   113                                  
   114 00000059 B9E007                  	mov	cx, 0x07E0
   115 0000005C 8EC1                    	mov	es, cx
   116 0000005E 8A0E[0300]              	mov	cl, [data.sects]	;# sectors
   117 00000062 30ED                    	xor	ch, ch
   118 00000064 E80F00                  	call	read_sectors
   119                                  
   120 00000067 BAF203                          mov     dx,03F2h	;Shut off floppy motor
   121 0000006A 30C0                            xor     al,al
   122 0000006C EE                              out     dx,al
   123                                  
   124 0000006D E90000                  	jmp	init
   125                                  
   126                                  init: 				; BOGUS, jmps to 512
   127                                  
   128                                  ;--------------------------------------------------------------------
   129                                  
   130                                  
   131 00000070 0100                    sect	dw	1	;Current location (0-based)
   132 00000072 0000                    track	dw	0
   133 00000074 0000                    head	dw	0
   134                                  
   135                                  
   136                                  read_sectors:
   137                                  ;;
   138                                  ;; CX = number of sectors to load
   139                                  ;; ES:0 = address to load at
   140                                  ;;
   141                                  ;; John Fine's BOOTP.ASM has a more elegant 'read_sectors'. I should steal
   142                                  ;; it :)
   143                                  ;;
   144                                  .track
   145 00000076 A1[C401]                	mov	ax, [sectors]
   146 00000079 2B06[7000]              	sub	ax, [sect]	;AX = # sectors to load on this track
   147 0000007D 39C8                    	cmp	ax, cx		;ax = min (ax, cx)
   148 0000007F 7202                    	jb	.1
   149 00000081 89C8                    	mov	ax, cx
   150                                  
   151 00000083 8CC3                    .1	mov	bx, es		;Crossing a 64k boundary? Lower AX.
   152 00000085 89DA                    	mov	dx, bx
   153 00000087 C1EA0C                  	shr	dx, 12		;round DX up to nearest 64k
   154 0000008A C1E20C                  	shl	dx, 12
   155 0000008D 81C20010                	add	dx, 0x1000
   156 00000091 29DA                    	sub	dx, bx		;DX = # sectors remaining in 64k segment
   157 00000093 C1EA05                  	shr	dx, 5
   158 00000096 39D0                    	cmp	ax, dx		;ax = min (ax, dx)
   159 00000098 7202                    	jb	.2
   160 0000009A 89D0                    	mov	ax, dx
   161                                  .2
   162                                  
   163 0000009C E83700                  	call	read_track
   164 0000009F 29C1                    	sub	cx, ax
   165                                  
   166 000000A1 89C2                    	mov	dx, ax		;Increment ES
   167 000000A3 C1E205                  	shl	dx, 5
   168 000000A6 8CC3                    	mov	bx, es
   169 000000A8 01D3                    	add	bx, dx
   170 000000AA 8EC3                    	mov	es, bx
   171                                  
   172 000000AC 0306[7000]              	add	ax, [sect]	;Increment current sector
   173 000000B0 3B06[C401]              	cmp	ax, [sectors]
   174 000000B4 7218                    	jb	.t1
   175 000000B6 31C0                    	xor	ax, ax		;Flip head
   176 000000B8 FF06[7400]              	inc word [head]
   177 000000BC 813E[7400]0200          	cmp word [head], 2
   178 000000C2 720A                    	jb	.t1
   179 000000C4 C706[7400]0000          	mov word [head], 0	;Next track
   180 000000CA FF06[7200]              	inc word [track]
   181                                  .t1
   182 000000CE A3[7000]                	mov	[sect], ax
   183 000000D1 09C9                    	or	cx, cx
   184 000000D3 75A1                    	jnz	.track
   185 000000D5 C3                      	ret
   186                                  
   187                                  
   188                                  read_track:
   189                                  ;; AX = # of sectors
   190 000000D6 60                      	pusha
   191 000000D7 B90300                  	mov	cx, 3		;# of retries
   192                                  .retry
   193 000000DA 50                      	push	ax
   194 000000DB 51                      	push	cx
   195 000000DC 31DB                    	xor	bx, bx
   196 000000DE 8A0E[7000]              	mov	cl, [sect]
   197 000000E2 FEC1                    	inc	cl		;1-based
   198 000000E4 8A2E[7200]              	mov	ch, [track]
   199 000000E8 8A16[CE01]              	mov	dl, [boot_drive]
   200 000000EC 8A36[7400]              	mov	dh, [head]
   201 000000F0 B402                    	mov	ah, 2
   202 000000F2 CD13                    	int	0x13
   203 000000F4 7206                    	jc	.error
   204 000000F6 81C40400                	add	sp, 2*2		;drop ax & cx
   205 000000FA 61                      	popa
   206 000000FB C3                      	ret
   207                                  .error
   208 000000FC 59                      	pop	cx
   209 000000FD 58                      	pop	ax
   210 000000FE E2DA                    	loop	.retry
   211 00000100 E82B00                  	call	debug
   212 00000103 BD[B501]                	mov	bp, disk_error_msg	;Then give up.
   213 00000106 E87F00                  	call	print_string
   214 00000109 EBFE                    	jmp short $
   215                                  
   216                                  
   217                                  ;--------------------------------------------------------------------
   218                                  
   219                                  
   220                                  probe:
   221                                  ;
   222                                  ; Get disk parameters (by trial & error). Try 36, 18, 15, and 9 sectors
   223                                  ;
   224 0000010B BE[CA01]                        mov     si, DiskSizes
   225                                  .loop
   226 0000010E AC                              lodsb   ;AL=[SI]
   227 0000010F 98                              cbw     ;AX=AL (extended to word length)
   228 00000110 A3[C401]                        mov     [sectors], ax
   229 00000113 81FE[CE01]                      cmp     si, DiskSizes+4
   230 00000117 7314                            jae     .done
   231 00000119 91                              xchg    ax, cx
   232 0000011A 31D2                            xor     dx, dx
   233 0000011C 30DB                            xor     bl, bl
   234 0000011E 8A3E[C401]                      mov     bh, [sectors]
   235 00000122 FEC7                            inc     bh
   236 00000124 D0E7                            shl     bh, 1
   237 00000126 B80102                          mov     ax, 0x0201
   238 00000129 CD13                            int     0x13
   239 0000012B 72E1                            jc      .loop
   240                                  .done
   241 0000012D C3                      	ret
   242                                  
   243                                  
   244                                  
   245                                  debug:
   246 0000012E 60                      	pusha
   247 0000012F 52                      	push	dx
   248 00000130 51                      	push	cx
   249 00000131 53                      	push	bx
   250 00000132 50                      	push	ax
   251 00000133 9C                      	pushf
   252 00000134 E80600                  	call    print_all
   253 00000137 81C40A00                	add	sp, 5*2
   254 0000013B 61                      	popa
   255 0000013C C3                      	ret
   256                                  
   257                                  
   258                                  
   259                                  print_all:
   260                                  ;
   261                                  ; Register debugging dump (borrowed from Linux bootloader)
   262                                  ; Expects this on stack: dx, cx, bx, ax, errorcode
   263                                  ;
   264 0000013D B90500                          mov     cx,5    ;1 error code + 4 registers
   265 00000140 89E5                            mov     bp,sp
   266                                  .print_loop:
   267 00000142 51                              push    cx      ;save CX reg
   268 00000143 E81F00                          call    print_nl
   269                                  
   270 00000146 80F905                          cmp     cl,5    ;if (cx < 5) skip the next part
   271 00000149 730F                            jae     .no_reg
   272                                  
   273 0000014B B8450E                          mov     ax,0E05h + 'A' - 1
   274 0000014E 28C8                            sub     al,cl
   275 00000150 CD10                            int     10h
   276 00000152 B058                            mov     al,'X'
   277 00000154 CD10                            int     10h
   278 00000156 B03A                            mov     al,':'
   279 00000158 CD10                            int     10h
   280                                  .no_reg:
   281 0000015A 81C50200                        add     bp,2
   282 0000015E E80E00                          call    hex_print
   283 00000161 59                              pop     cx
   284 00000162 E2DE                            loop    .print_loop
   285 00000164 C3                              ret
   286                                  
   287                                  
   288                                  
   289                                  ; Supporting print functions
   290                                  print_nl:
   291 00000165 B80D0E                          mov     ax,0E0Dh        ;Service 0E=TTY character output
   292 00000168 CD10                            int     10h
   293 0000016A B00A                            mov     al,0Ah
   294 0000016C CD10                            int     10h
   295 0000016E C3                              ret
   296                                  
   297                                  
   298                                  
   299                                  hex_print:
   300                                  ;
   301                                  ; Prints the word at (ss:bp)
   302                                  ;
   303 0000016F B90400                          mov     cx,4
   304 00000172 8B5600                          mov     dx,[bp]
   305                                  print_digit:
   306 00000175 C1C204                          rol     dx,4
   307 00000178 B80F0E                          mov     ax,0E0Fh
   308 0000017B 20D0                            and     al,dl
   309 0000017D 0490                            add     al,90h
   310 0000017F 27                              daa
   311 00000180 1440                            adc     al,40h
   312 00000182 27                              daa
   313 00000183 CD10                            int     10h
   314 00000185 E2EE                            loop    print_digit
   315 00000187 C3                              ret
   316                                  
   317                                  
   318                                  
   319                                  print_string:
   320                                  ;
   321                                  ; Let ES:BP point to a null-terminated string
   322                                  ;
   323 00000188 B40E                            mov     ah,0Eh
   324 0000018A BB0000                          mov     bx,0            ;Set video page & Text olor
   325 0000018D 3E807E0000              .l1     cmp     [ds:bp],byte 0
   326 00000192 740A                            je      .end
   327 00000194 3E8A4600                        mov     al,[ds:bp]
   328 00000198 CD10                            int     10h
   329 0000019A 45                              inc     bp
   330 0000019B E9EFFF                          jmp     .l1
   331 0000019E C3                      .end    ret
   332                                  
   333                                  ;--------------------------------------------------------------------
   334                                  
   335 0000019F 524554524F20233920-     boot_msg	db "RETRO #9 bootloader",13,10,0
   336 000001A8 626F6F746C6F616465-
   337 000001B1 720D0A00           
   338                                  ;boot_msg	db "RETRO #9 bootloader, ",DATE," by ",USER,13,10,0
   339                                  
   340 000001B5 0D0A4469736B204572-     disk_error_msg	db 13,10,"Disk Error",13,10,0
   341 000001BE 726F720D0A00       
   342                                  
   343                                  
   344                                  ;Disk specs
   345 000001C4 0000                    sectors:        dw      0
   346 000001C6 5000                    tracks:		dw	80
   347 000001C8 0200                    heads:		dw	2
   348                                  
   349 000001CA 24120F09                DiskSizes	db 36,18,15,9
   350                                  
   351 000001CE 00                      boot_drive	db 0		; Boot drive (initial value of DL)
   352                                  
   353                                  
   354 000001CF 00<rept>                times	510-($-$$)	db 0	; skip to end of sector
   355 000001FE 55AA                    	dw	0xAA55		; boot sector signature
   356                                  
   357                                  
   358                                  
   359                                  
   360                                  modules_start:
   361                                  ; Any modules concatenated to the boot image will be right here.
   362                                  ;
   363                                  ; Note: The boot sector won't load the modules unless the 'num_sectors'
   364                                  ; field in the data block is increased to account for the modules.  Do this
   365                                  ; by running the 'adjboot' utility after tacking on the modules.
   366                                  
   367                                  
   368                                  ;boot_size	equ	$-boot_start
   369                                  ;num_sectors	equ	(boot_size - (boot_size % 512) ) / 512
   370                                  num_sectors	equ	1
