| 1 | /* |
| 2 | * Minimal Alpha system boot code. |
| 3 | * |
| 4 | * Copyright Linaro Ltd 2019 |
| 5 | */ |
| 6 | |
| 7 | .set noat |
| 8 | .set nomacro |
| 9 | .arch ev6 |
| 10 | .text |
| 11 | |
| 12 | .macro load_pci_io reg |
| 13 | /* For typhoon, this is |
| 14 | * 0xfffffc0000000000 -- kseg identity map |
| 15 | * + 0x10000000000 -- typhoon pio base |
| 16 | * + 0x1fc000000 -- typhoon pchip0 pci base |
| 17 | * = 0xfffffd01fc000000 |
| 18 | */ |
| 19 | ldah \reg, -3 /* ff..fd0000 */ |
| 20 | lda \reg, 0x1fc(\reg) /* ff..fd01fc */ |
| 21 | sll \reg, 24, \reg |
| 22 | .endm |
| 23 | |
| 24 | #define com1Rbr 0x3f8 |
| 25 | #define com1Thr 0x3f8 |
| 26 | #define com1Ier 0x3f9 |
| 27 | #define com1Iir 0x3fa |
| 28 | #define com1Lcr 0x3fb |
| 29 | #define com1Mcr 0x3fc |
| 30 | #define com1Lsr 0x3fd |
| 31 | #define com1Msr 0x3fe |
| 32 | #define com1Scr 0x3ff |
| 33 | #define com1Dll 0x3f8 |
| 34 | #define com1Dlm 0x3f9 |
| 35 | |
| 36 | #define PAL_halt 0 |
| 37 | #define PAL_wrent 52 |
| 38 | #define PAL_wrkgp 55 |
| 39 | |
| 40 | .text |
| 41 | .p2align 4 |
| 42 | .globl _start |
| 43 | .ent _start |
| 44 | _start: |
| 45 | br $gp, .+4 |
| 46 | ldah $gp, 0($gp) !gpdisp!1 |
| 47 | lda $gp, 0($gp) !gpdisp!1 |
| 48 | |
| 49 | ldah $sp, $stack_end($gp) !gprelhigh |
| 50 | lda $sp, $stack_end($sp) !gprellow |
| 51 | |
| 52 | /* Install kernel gp for exception handlers. */ |
| 53 | mov $gp, $16 |
| 54 | call_pal PAL_wrkgp |
| 55 | |
| 56 | /* Install exception handlers. */ |
| 57 | ldah $16, entInt($gp) !gprelhigh |
| 58 | lda $16, entInt($16) !gprellow |
| 59 | lda $17, 0 |
| 60 | call_pal PAL_wrent |
| 61 | |
| 62 | ldah $16, entArith($gp) !gprelhigh |
| 63 | lda $16, entArith($16) !gprellow |
| 64 | lda $17, 1 |
| 65 | call_pal PAL_wrent |
| 66 | |
| 67 | ldah $16, entMM($gp) !gprelhigh |
| 68 | lda $16, entMM($16) !gprellow |
| 69 | lda $17, 2 |
| 70 | call_pal PAL_wrent |
| 71 | |
| 72 | ldah $16, entIF($gp) !gprelhigh |
| 73 | lda $16, entIF($16) !gprellow |
| 74 | lda $17, 3 |
| 75 | call_pal PAL_wrent |
| 76 | |
| 77 | ldah $16, entUna($gp) !gprelhigh |
| 78 | lda $16, entUna($16) !gprellow |
| 79 | lda $17, 4 |
| 80 | call_pal PAL_wrent |
| 81 | |
| 82 | ldah $16, entSys($gp) !gprelhigh |
| 83 | lda $16, entSys($16) !gprellow |
| 84 | lda $17, 5 |
| 85 | call_pal PAL_wrent |
| 86 | |
| 87 | /* |
| 88 | * Initialize COM1. |
| 89 | */ |
| 90 | load_pci_io $1 |
| 91 | lda $2, 0x87 /* outb(0x87, com1Lcr); */ |
| 92 | stb $2, com1Lcr($1) |
| 93 | stb $31, com1Dlm($1) /* outb(0, com1Dlm); */ |
| 94 | lda $2, 3 /* baudconst 3 => 56000 */ |
| 95 | stb $2, com1Dll($1) /* outb(baudconst, com1Dll); */ |
| 96 | lda $2, 0x07 |
| 97 | stb $2, com1Lcr($1) /* outb(0x07, com1Lcr) */ |
| 98 | lda $2, 0x0f |
| 99 | stb $2, com1Mcr($1) /* outb(0x0f, com1Mcr) */ |
| 100 | |
| 101 | bsr $26, main !samegp |
| 102 | |
| 103 | /* fall through to _exit */ |
| 104 | .end _start |
| 105 | |
| 106 | .globl _exit |
| 107 | .ent _exit |
| 108 | _exit: |
| 109 | .frame $sp, 0, $26, 0 |
| 110 | .prologue 0 |
| 111 | |
| 112 | /* We cannot return an error code. */ |
| 113 | call_pal PAL_halt |
| 114 | .end _exit |
| 115 | |
| 116 | /* |
| 117 | * We have received an exception that we don't handle. Log and exit. |
| 118 | */ |
| 119 | .ent log_exit |
| 120 | log_exit: |
| 121 | entInt: |
| 122 | entArith: |
| 123 | entMM: |
| 124 | entIF: |
| 125 | entUna: |
| 126 | entSys: |
| 127 | ldah $16, $errormsg($gp) !gprelhigh |
| 128 | lda $16, $errormsg($16) !gprellow |
| 129 | bsr $26, __sys_outs !samegp |
| 130 | bsr $26, _exit !samegp |
| 131 | .end log_exit |
| 132 | |
| 133 | .section .rodata |
| 134 | $errormsg: |
| 135 | .string "Terminated by exception.\n" |
| 136 | .previous |
| 137 | |
| 138 | /* |
| 139 | * Helper Functions |
| 140 | */ |
| 141 | |
| 142 | /* Output a single character to serial port */ |
| 143 | .global __sys_outc |
| 144 | .ent __sys_outc |
| 145 | __sys_outc: |
| 146 | .frame $sp, 0, $26, 0 |
| 147 | .prologue 0 |
| 148 | |
| 149 | load_pci_io $1 |
| 150 | |
| 151 | /* |
| 152 | * while ((inb(com1Lsr) & 0x20) == 0) |
| 153 | * continue; |
| 154 | */ |
| 155 | 1: ldbu $0, com1Lsr($1) |
| 156 | and $0, 0x20, $0 |
| 157 | beq $0, 1b |
| 158 | |
| 159 | /* outb(c, com1Thr); */ |
| 160 | stb $16, com1Thr($1) |
| 161 | ret |
| 162 | .end __sys_outc |
| 163 | |
| 164 | /* Output a nul-terminated string to serial port */ |
| 165 | .global __sys_outs |
| 166 | .ent __sys_outs |
| 167 | __sys_outs: |
| 168 | .frame $sp, 0, $26, 0 |
| 169 | .prologue 0 |
| 170 | |
| 171 | load_pci_io $1 |
| 172 | |
| 173 | ldbu $2, 0($16) |
| 174 | beq $2, 9f |
| 175 | |
| 176 | /* |
| 177 | * while ((inb(com1Lsr) & 0x20) == 0) |
| 178 | * continue; |
| 179 | */ |
| 180 | 1: ldbu $0, com1Lsr($1) |
| 181 | and $0, 0x20, $0 |
| 182 | beq $0, 1b |
| 183 | |
| 184 | /* outb(c, com1Thr); */ |
| 185 | stb $2, com1Thr($1) |
| 186 | |
| 187 | addq $16, 1, $16 |
| 188 | ldbu $2, 0($16) |
| 189 | bne $2, 1b |
| 190 | |
| 191 | 9: ret |
| 192 | .end __sys_outs |
| 193 | |
| 194 | /* |
| 195 | * Division routines that are normally in libc. |
| 196 | * |
| 197 | * These do not follow the C calling convention. Arguments are in $24+$25, |
| 198 | * the result is in $27. Register $28 may be clobbered; everything else |
| 199 | * must be saved. |
| 200 | * |
| 201 | * We store the remainder in $28, so that we can share code. |
| 202 | * |
| 203 | * We do not signal divide by zero. |
| 204 | */ |
| 205 | |
| 206 | /* |
| 207 | * Unsigned 64-bit division. |
| 208 | */ |
| 209 | |
| 210 | .globl __divqu |
| 211 | .ent __divqu |
| 212 | __divqu: |
| 213 | .frame $sp, 48, $23 |
| 214 | subq $sp, 48, $sp |
| 215 | stq $0, 0($sp) |
| 216 | stq $1, 8($sp) |
| 217 | stq $2, 16($sp) |
| 218 | stq $3, 24($sp) |
| 219 | stq $4, 32($sp) |
| 220 | .prologue 0 |
| 221 | |
| 222 | #define mask $0 |
| 223 | #define divisor $1 |
| 224 | #define compare $2 |
| 225 | #define tmp1 $3 |
| 226 | #define tmp2 $4 |
| 227 | #define quotient $27 |
| 228 | #define modulus $28 |
| 229 | |
| 230 | mov $24, modulus |
| 231 | mov $25, divisor |
| 232 | mov $31, quotient |
| 233 | mov 1, mask |
| 234 | beq $25, 9f |
| 235 | |
| 236 | /* Shift left until divisor >= modulus. */ |
| 237 | 1: cmpult divisor, modulus, compare |
| 238 | blt divisor, 2f |
| 239 | addq divisor, divisor, divisor |
| 240 | addq mask, mask, mask |
| 241 | bne compare, 1b |
| 242 | |
| 243 | 2: addq quotient, mask, tmp2 |
| 244 | srl mask, 1, mask |
| 245 | cmpule divisor, modulus, compare |
| 246 | subq modulus, divisor, tmp1 |
| 247 | cmovne compare, tmp2, quotient |
| 248 | srl divisor, 1, divisor |
| 249 | cmovne compare, tmp1, modulus |
| 250 | bne mask, 2b |
| 251 | |
| 252 | 9: ldq $0, 0($sp) |
| 253 | ldq $1, 8($sp) |
| 254 | ldq $2, 16($sp) |
| 255 | ldq $3, 24($sp) |
| 256 | ldq $4, 32($sp) |
| 257 | addq $sp, 48, $sp |
| 258 | ret $31, ($23), 1 |
| 259 | |
| 260 | #undef mask |
| 261 | #undef divisor |
| 262 | #undef compare |
| 263 | #undef tmp1 |
| 264 | #undef tmp2 |
| 265 | #undef quotient |
| 266 | #undef modulus |
| 267 | |
| 268 | .end __divqu |
| 269 | |
| 270 | /* |
| 271 | * Unsigned 64-bit remainder. |
| 272 | * Note that __divqu above leaves the result in $28. |
| 273 | */ |
| 274 | |
| 275 | .globl __remqu |
| 276 | .ent __remqu |
| 277 | __remqu: |
| 278 | .frame $sp, 16, $23 |
| 279 | subq $sp, 16, $sp |
| 280 | stq $23, 0($sp) |
| 281 | .prologue 0 |
| 282 | |
| 283 | bsr $23, __divqu |
| 284 | |
| 285 | ldq $23, 0($sp) |
| 286 | mov $28, $27 |
| 287 | addq $sp, 16, $sp |
| 288 | ret $31, ($23), 1 |
| 289 | .end __remqu |
| 290 | |
| 291 | /* |
| 292 | * Signed 64-bit division. |
| 293 | */ |
| 294 | |
| 295 | .globl __divqs |
| 296 | .ent __divqs |
| 297 | __divqs: |
| 298 | .prologue 0 |
| 299 | |
| 300 | /* Common case: both arguments are positive. */ |
| 301 | bis $24, $25, $28 |
| 302 | bge $28, __divqu |
| 303 | |
| 304 | /* At least one argument is negative. */ |
| 305 | subq $sp, 32, $sp |
| 306 | stq $23, 0($sp) |
| 307 | stq $24, 8($sp) |
| 308 | stq $25, 16($sp) |
| 309 | |
| 310 | /* Compute absolute values. */ |
| 311 | subq $31, $24, $28 |
| 312 | cmovlt $24, $28, $24 |
| 313 | subq $31, $25, $28 |
| 314 | cmovlt $25, $28, $25 |
| 315 | |
| 316 | bsr $23, __divqu |
| 317 | |
| 318 | ldq $24, 8($sp) |
| 319 | ldq $25, 16($sp) |
| 320 | |
| 321 | /* -a / b = a / -b = -(a / b) */ |
| 322 | subq $31, $27, $23 |
| 323 | xor $24, $25, $28 |
| 324 | cmovlt $28, $23, $27 |
| 325 | |
| 326 | ldq $23, 0($sp) |
| 327 | addq $sp, 32, $sp |
| 328 | ret $31, ($23), 1 |
| 329 | .end __divqs |
| 330 | |
| 331 | /* |
| 332 | * Signed 64-bit remainder. |
| 333 | */ |
| 334 | |
| 335 | .globl __remqs |
| 336 | .ent __remqs |
| 337 | __remqs: |
| 338 | .prologue 0 |
| 339 | |
| 340 | /* Common case: both arguments are positive. */ |
| 341 | bis $24, $25, $28 |
| 342 | bge $28, __remqu |
| 343 | |
| 344 | /* At least one argument is negative. */ |
| 345 | subq $sp, 32, $sp |
| 346 | stq $23, 0($sp) |
| 347 | stq $24, 8($sp) |
| 348 | stq $25, 16($sp) |
| 349 | |
| 350 | /* Compute absolute values. */ |
| 351 | subq $31, $24, $28 |
| 352 | cmovlt $24, $28, $24 |
| 353 | subq $31, $25, $28 |
| 354 | cmovlt $25, $28, $25 |
| 355 | |
| 356 | bsr $23, __divqu |
| 357 | |
| 358 | ldq $23, 0($sp) |
| 359 | ldq $24, 8($sp) |
| 360 | ldq $25, 16($sp) |
| 361 | |
| 362 | /* -a % b = -(a % b); a % -b = a % b. */ |
| 363 | subq $31, $28, $27 |
| 364 | cmovge $24, $28, $27 |
| 365 | |
| 366 | addq $sp, 32, $sp |
| 367 | ret $31, ($23), 1 |
| 368 | .end __remqs |
| 369 | |
| 370 | /* |
| 371 | * Unsigned 32-bit division. |
| 372 | */ |
| 373 | |
| 374 | .globl __divlu |
| 375 | .ent __divlu |
| 376 | __divlu: |
| 377 | .frame $sp, 32, $23 |
| 378 | subq $sp, 32, $sp |
| 379 | stq $23, 0($sp) |
| 380 | stq $24, 8($sp) |
| 381 | stq $25, 16($sp) |
| 382 | .prologue 0 |
| 383 | |
| 384 | /* Zero extend and use the 64-bit routine. */ |
| 385 | zap $24, 0xf0, $24 |
| 386 | zap $25, 0xf0, $25 |
| 387 | bsr $23, __divqu |
| 388 | |
| 389 | addl $27, 0, $27 |
| 390 | ldq $23, 0($sp) |
| 391 | ldq $24, 8($sp) |
| 392 | ldq $25, 16($sp) |
| 393 | addq $sp, 32, $sp |
| 394 | ret $31, ($23), 1 |
| 395 | .end __divlu |
| 396 | |
| 397 | /* |
| 398 | * Unsigned 32-bit remainder. |
| 399 | */ |
| 400 | |
| 401 | .globl __remlu |
| 402 | .ent __remlu |
| 403 | __remlu: |
| 404 | .frame $sp, 32, $23 |
| 405 | subq $sp, 32, $sp |
| 406 | stq $23, 0($sp) |
| 407 | stq $24, 8($sp) |
| 408 | stq $25, 16($sp) |
| 409 | .prologue 0 |
| 410 | |
| 411 | /* Zero extend and use the 64-bit routine. */ |
| 412 | zap $24, 0xf0, $24 |
| 413 | zap $25, 0xf0, $25 |
| 414 | bsr $23, __divqu |
| 415 | |
| 416 | /* Recall that the remainder is returned in $28. */ |
| 417 | addl $28, 0, $27 |
| 418 | ldq $23, 0($sp) |
| 419 | ldq $24, 8($sp) |
| 420 | ldq $25, 16($sp) |
| 421 | addq $sp, 32, $sp |
| 422 | ret $31, ($23), 1 |
| 423 | .end __remlu |
| 424 | |
| 425 | /* |
| 426 | * Signed 32-bit division. |
| 427 | */ |
| 428 | |
| 429 | .globl __divls |
| 430 | .ent __divls |
| 431 | __divls: |
| 432 | .frame $sp, 32, $23 |
| 433 | subq $sp, 32, $sp |
| 434 | stq $23, 0($sp) |
| 435 | stq $24, 8($sp) |
| 436 | stq $25, 16($sp) |
| 437 | .prologue 0 |
| 438 | |
| 439 | /* Sign extend. */ |
| 440 | addl $24, 0, $24 |
| 441 | addl $25, 0, $25 |
| 442 | |
| 443 | /* Compute absolute values. */ |
| 444 | subq $31, $24, $28 |
| 445 | cmovlt $24, $28, $24 |
| 446 | subq $31, $25, $28 |
| 447 | cmovlt $25, $28, $25 |
| 448 | |
| 449 | bsr $23, __divqu |
| 450 | |
| 451 | ldq $24, 8($sp) |
| 452 | ldq $25, 16($sp) |
| 453 | |
| 454 | /* Negate the unsigned result, if necessary. */ |
| 455 | xor $24, $25, $28 |
| 456 | subl $31, $27, $23 |
| 457 | addl $27, 0, $27 |
| 458 | addl $28, 0, $28 |
| 459 | cmovlt $28, $23, $27 |
| 460 | |
| 461 | ldq $23, 0($sp) |
| 462 | addq $sp, 32, $sp |
| 463 | ret $31, ($23), 1 |
| 464 | .end __divls |
| 465 | |
| 466 | /* |
| 467 | * Signed 32-bit remainder. |
| 468 | */ |
| 469 | |
| 470 | .globl __remls |
| 471 | .ent __remls |
| 472 | __remls: |
| 473 | .frame $sp, 32, $23 |
| 474 | subq $sp, 32, $sp |
| 475 | stq $23, 0($sp) |
| 476 | stq $24, 8($sp) |
| 477 | stq $25, 16($sp) |
| 478 | .prologue 0 |
| 479 | |
| 480 | /* Sign extend. */ |
| 481 | addl $24, 0, $24 |
| 482 | addl $25, 0, $25 |
| 483 | |
| 484 | /* Compute absolute values. */ |
| 485 | subq $31, $24, $28 |
| 486 | cmovlt $24, $28, $24 |
| 487 | subq $31, $25, $28 |
| 488 | cmovlt $25, $28, $25 |
| 489 | |
| 490 | bsr $23, __divqu |
| 491 | |
| 492 | ldq $23, 0($sp) |
| 493 | ldq $24, 8($sp) |
| 494 | ldq $25, 16($sp) |
| 495 | |
| 496 | /* Negate the unsigned result, if necessary. */ |
| 497 | subl $31, $28, $27 |
| 498 | addl $28, 0, $28 |
| 499 | cmovge $24, $28, $27 |
| 500 | |
| 501 | addq $sp, 32, $sp |
| 502 | ret $31, ($23), 1 |
| 503 | .end __remls |
| 504 | |
| 505 | .data |
| 506 | .p2align 4 |
| 507 | stack: |
| 508 | .skip 65536 |
| 509 | $stack_end: |
| 510 | .type stack,@object |
| 511 | .size stack, . - stack |