1/* $MirOS: src/sys/arch/i386/stand/bootxx/bootxx.S,v 1.26 2010/12/01 19:56:58 tg Exp $ */ 2 3/*- 4 * Copyright (c) 2009 5 * Thorsten Glaser <tg@mirbsd.org> 6 * 7 * Provided that these terms and disclaimer and all copyright notices 8 * are retained or reproduced in an accompanying document, permission 9 * is granted to deal in this work without restriction, including un- 10 * limited rights to use, publicly perform, distribute, sell, modify, 11 * merge, give away, or sublicence. 12 * 13 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 14 * the utmost extent permitted by applicable law, neither express nor 15 * implied; without malicious intent or gross negligence. In no event 16 * may a licensor, author or contributor be held liable for indirect, 17 * direct, other damage, loss, or other issues arising in any way out 18 * of dealing in the work, even if advised of the possibility of such 19 * damage or existence of a defect, except proven that it results out 20 * of said person's immediate fault when using the work as intended. 21 */ 22 23 .intel_syntax noprefix 24 .section .comment 25 .ascii "$MirOS: src/sys/arch/i386/stand/bootxx/bootxx.S,v 1.26 2010/12/01 19:56:58 tg Exp $" 26#if defined(BOOT_GRUB) 27 .ascii " +t:GRUB" 28#elif defined(BOOT_ISOLINUX) 29 .ascii " +t:ILNX" 30#else 31 .ascii " +t:MBSD" 32#endif 33#ifdef BPB_SPACE 34 .ascii " +s:BPB" 35#else 36 .ascii " +s:MBR" 37#endif 38 .byte 0 39 40 .code16 41 .text 42 43 .globl _start 44 .type _start,@function 45_start: /* bootxx entry point 07C00 */ 46#ifdef BPB_SPACE 47 jmp Linit 48 nop 49 . = _start + 3 50L_BPB: .ascii "MirOSBSD" 51 . = L_BPB + 0x3F 52 .byte 0x29 53 . = L_BPB + 0x44 54 .ascii "MirOSBSDldr" 55 .ascii "FATnn " 56#endif 57Linit: xor ecx,ecx 58 mov ss,cx 59 mov sp,0x7BFC 60 push ecx 61 popfd 62#ifdef BOOT_ISOLINUX 63 push es /* $PnP header */ 64 push di 65#endif 66 mov es,cx 67#if defined(BOOT_GRUB) || defined(BOOT_ISOLINUX) 68 mov si,0x7C00 /* 0000:_start pre-reloc */ 69#else 70 mov di,0x7C00 /* DS:SI is set by BIOS! */ 71 push di 72 /* save partition table entry */ 73 mov cl,16 74 rep movsb 75 pop si 76#endif 77 mov ds,cx 78 mov bx,SA_LINKSEG 79 push bx 80 push bx 81 mov es,bx 82 mov di,offset _start 83 mov ch,2 /* 512 bytes */ 84 rep movsb 85 pop ds 86 push offset Lmain 87 lret 88 89 Lpblk = _start + 0x10 90 Lebss = Lpblk + 0x18 /* make sure this is < Lmmsg */ 91 92Lemsg: .ascii __BOOT_VER 93 .asciz " Loading " 94#ifndef BOOT_GRUB 95Lmmsg: .ascii "bad magic" 96#endif 97Lfmsg: .ascii " error" 98Lbmsg: .asciz "\r\n" 99 100 .globl bkcnt 101 .type bkcnt,@object 102 .size bkcnt,1 103bkcnt: .byte (bkend - bktbl) 104 105 .globl geomh 106 .type geomh,@object 107 .size geomh,2 108geomh: .word 2 /* 1..256 = tracks per cylinder */ 109 110 .globl geoms 111 .type geoms,@object 112 .size geoms,2 113 /* set to 0 for auto geometry */ 114geoms: .word 18 /* 1..63 = sectors per track */ 115 116 .globl partp 117 .type partp,@object 118 .size partp,1 119partp: .byte 0 120Ldrv: .byte 0x80 /* must be at partp + 1 */ 121 122Lload: .word LsLBA 123 124#ifdef BOOT_ISOLINUX 125Lpnp: .long 0 126#endif 127 128 /* output NUL-terminated string from ds:si */ 129Lotxt0: mov ah,0x0E 130 mov bx,7 131 int 0x10 132Lotxt: lodsb 133 or al,al 134 jnz Lotxt0 135 ret 136 137Lbarf: call Lotxt 138 mov ax,offset LsCHS 139 xchg ax,[Lload] 140 cmp ax,offset LsCHS 141 jne Lretr 142 xor ax,ax 143 int 0x16 144 jmp 0xF000,0xFFF0 145 146Lmain: sti 147 mov [Ldrv],dl 148#ifdef BOOT_ISOLINUX 149 pop eax /* $PnP header */ 150 mov [Lpnp],eax 151#endif 152 mov si,offset Lemsg 153 cmp dl,0x80 154 jb Lbarf /* floppy: only try CHS */ 155 call Lotxt 156 /* FALLTHROUGH */ 157 158Lretr: xor bx,bx /* load offset (begin) */ 159 mov si,offset bktbl 160 movzx bp,byte ptr [bkcnt] 161Lloop: lodsb 162 /*- 163 * AL contains bitmasked: aaabbbbb 164 * -> a = (number of bytes - 1) that follow (-> CX) 165 * -> b = (number of sectors - 1) to load (-> DI) 166 * BX contains current load address offset 167 * SI contains pointer to data being processed 168 * BP contains number of entries to process 169 */ 170 171 /* decode */ 172 movzx cx,al 173 shr cl,5 174 and ax,0x1F 175 inc ax 176 inc cx 177 push ax /* later DI */ 178 179 /* create LBA parameter block */ 180 mov di,offset Lpblk 181 mov ax,0x0010 182 stosw 183 mov al,1 184 stosw 185 mov ax,bx 186 stosw 187 mov ax,cs 188 stosw 189 rep movsb /* copy CX bytes */ 190 xor ax,ax /* pad with 8 (up to 7 needed) NUL bytes */ 191 stosw 192 stosw 193 stosw 194 stosw 195 196 pop di 197 /*- 198 * Lpblk, Ldrv are filled in completely 199 * CS = DS = ES = SA_LINKSEG = 0x4000 200 * DI = number of sectors to still load 201 * BX = load offset (segment CS) 202 * BP = number of entries to load, including this one 203 * SI = pointer to next entry to load 204 */ 205 push bp 206 push si 207Lld1s: mov si,offset Lpblk 208 call [Lload] 209 mov bp,4 /* number of retries */ 210 mov dl,[Ldrv] 211Lldlp: pusha 212 stc 213 int 0x13 214 pushf 215 mov ax,0x0E2E /* "dot" as progress meter */ 216 mov bx,7 217 int 0x10 218 popf 219 sti 220 popa 221 jnc Lldok 222 dec bp 223 pusha 224 pushf 225 xor ax,ax /* reset drive */ 226 int 0x13 227 popf 228 mov si,offset Lfmsg 229 jz Lbarf 230 mov ax,0x0E30 /* number as fail meter */ 231 add ax,bp 232 mov bx,7 233 int 0x10 234 popa 235 jmp Lldlp 236Lldok: /* increment load address by sector size */ 237 mov ah,2 /* 512 bytes */ 238 .globl secsz 239 .type secsz,@object 240 .size secsz,1 241 secsz = . - 1 /* the "2" above */ 242L...1: add bh,ah /* add the 512 bytes */ 243 mov 4[si],bx 244 add ah,bh /* again */ 245 jc Ldone /* last block completes (64 KiB - bootxx) */ 246 /* increment quadword by one */ 247 add dword ptr 8[si],1 248 adc dword ptr 12[si],0 249 /* load next sector */ 250 dec di 251 jnz Lld1s 252 pop si 253 pop bp 254 dec bp 255 jnz Lloop 256 /* FALLTHROUGH */ 257 258Ldone: /* check bootloader magic */ 259#if defined(BOOT_GRUB) 260 /* no magic */ 261#elif defined(BOOT_ISOLINUX) 262 xor ecx,ecx 263 push ecx /* partition offset (qword) */ 264 push ecx /* partition offset (qword) */ 265 mov eax,[Lpnp] 266 push eax /* ES, DI */ 267 mov ax,[Ldrv] 268 push ax /* DX */ 269 mov ax,[geomh] 270 push ax /* # of heads */ 271 mov ax,[geoms] 272 push ax /* # of sectors per track */ 273 xor bx,bx 274 mov ax,[Lload] 275 cmp ax,offset LsCHS /* so-called CBIOS */ 276 je Lilx1 277 inc bx /* so-called EBIOS */ 278Lilx1: push bx /* ebios flag */ 279 push cx /* target CS */ 280 mov eax,ds:[0x40] /* location of magic in ISOLINUX.BIN */ 281 mov si,offset Lmmsg 282 cmp eax,0x7078C0FB /* magic */ 283 jne Lbarf 284#else 285 xor eax,eax 286 push ax /* return address */ 287 mov ax,[partp] 288 xchg eax,ds:[4] /* location of magic in /boot */ 289 cmp eax,0x696D4F00 290 mov si,offset Lmmsg 291 jne Lbarf 292#endif 293 mov si,offset Lbmsg 294 call Lotxt 295#if defined(BOOT_GRUB) || defined(BOOT_ISOLINUX) 296#if defined(BOOT_GRUB) 297 xor edx,edx 298 push dx /* initial CS */ 299 dec edx /* EDX := FFFFFFFF */ 300 mov dl,[Ldrv] /* boot BIOS drive number */ 301 mov ax,0x8200 302#elif defined(BOOT_ISOLINUX) 303 mov ax,0x7C44 304#endif 305 push ax /* initial IP */ 306 cli /* be nice to a GNU every once in a while */ 307 lret 308#else 309 mov si,offset _start 310 ret 311#endif 312 313 /* obtain drive geometry */ 314Lgeom: pusha 315 push es 316#if 0 317 /* 318 * According to RBIL, this is needed to guard against 319 * BIOS bugs, but we don’t read out the table anyway. 320 */ 321 xor di,di 322 mov es,di 323#endif 324 mov ah,8 325 mov dl,[Ldrv] 326 stc 327 int 0x13 328 sti 329 pop es 330 mov si,offset Lfmsg 331 jc Lbarf 332 /* process returned values */ 333 and cl,0x3F /* number of sectors per track */ 334 mov [geoms],cl /* high byte is 0 anyway */ 335 movzx ax,dh 336 inc ax /* maximum index -> number of heads */ 337 mov [geomh],ax 338 popa 339 /* FALLTHROUGH */ 340 341LsCHS: mov cx,[geoms] 342 jcxz Lgeom 343 mov ax,8[si] 344 mov dx,10[si] 345 div cx 346 inc dx /* remainder: sector */ 347 xor cx,cx 348 xchg cx,dx 349 div word ptr [geomh] 350 shl ah,6 /* quotient: cylinder */ 351 xchg ah,al 352 or cx,ax 353 mov dh,dl /* remainder: head */ 354 mov ax,0x0201 355 ret 356 357LsLBA: mov ah,0x42 358 ret 359 360 .globl bktbl 361 .type bktbl,@object 362bktbl: .long 0xCAFEBABE 363 364#ifndef BPB_SPACE 365 /* ensure we have space for a partition table */ 366 . = _start + 0x01BE 367 .byte 0 368#endif 369 370 /* bxinst requires bktbl to end at 510 */ 371 . = _start + 0x01FE 372 /* bkend is required by installboot(8) still */ 373 .globl bkend 374 .type bkend,@object 375bkend: .word 0xAA55 376