1/* $NetBSD: start_dos.S,v 1.1 2024/06/29 13:45:14 rin Exp $ */ 2 3/* 4 * startup for DOS .COM programs 5 * with input from: 6 * netbsd:sys/arch/i386/boot/start.S 7 * Tor Egge's patches for NetBSD boot (pr port-i386/1002) 8 * freebsd:sys/i386/boot/netboot/start2.S 9 * XMS support by Martin Husemann 10 */ 11 12/* 13 * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 14 * 15 * Mach Operating System 16 * Copyright (c) 1992, 1991 Carnegie Mellon University 17 * All Rights Reserved. 18 * 19 * Permission to use, copy, modify and distribute this software and its 20 * documentation is hereby granted, provided that both the copyright 21 * notice and this permission notice appear in all copies of the 22 * software, derivative works or modified versions, and any portions 23 * thereof, and that both notices appear in supporting documentation. 24 * 25 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 26 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 27 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 28 * 29 * Carnegie Mellon requests users of this software to return to 30 * 31 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 32 * School of Computer Science 33 * Carnegie Mellon University 34 * Pittsburgh PA 15213-3890 35 * 36 * any improvements or extensions that they make and grant Carnegie Mellon 37 * the rights to redistribute these changes. 38 */ 39 40/* 41 Copyright 1988, 1989, 1990, 1991, 1992 42 by Intel Corporation, Santa Clara, California. 43 44 All Rights Reserved 45 46Permission to use, copy, modify, and distribute this software and 47its documentation for any purpose and without fee is hereby 48granted, provided that the above copyright notice appears in all 49copies and that both the copyright notice and this permission notice 50appear in supporting documentation, and that the name of Intel 51not be used in advertising or publicity pertaining to distribution 52of the software without specific, written prior permission. 53 54INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 55INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 56IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 57CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 58LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 59NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 60WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 61*/ 62 63#include <machine/asm.h> 64 65 66CR0_PE = 0x1 67 68 .data 69 .globl _C_LABEL(ourseg) 70_C_LABEL(ourseg): 71 .long 0 72 73/************************************************************************** 74GLOBAL DESCRIPTOR TABLE 75**************************************************************************/ 76#ifdef __ELF__ 77 .align 16 78#else 79 .align 4 80#endif 81gdt: 82 .word 0, 0 83 .byte 0, 0x00, 0x00, 0 84 85#ifdef SUPPORT_LINUX /* additional dummy */ 86 .word 0, 0 87 .byte 0, 0x00, 0x00, 0 88#endif 89 90 /* kernel code segment */ 91 .globl flatcodeseg 92flatcodeseg = . - gdt 93 .word 0xffff, 0 94 .byte 0, 0x9f, 0xcf, 0 95 96 /* kernel data segment */ 97 .globl flatdataseg 98flatdataseg = . - gdt 99 .word 0xffff, 0 100 .byte 0, 0x93, 0xcf, 0 101 102 /* boot code segment, base will be patched */ 103bootcodeseg = . - gdt 104 .word 0xffff, 0 105 .byte 0, 0x9e, 0x40, 0 106 107 /* boot data segment, base will be patched */ 108bootdataseg = . - gdt 109#ifdef HEAP_BELOW_64K 110 .word 0xffff, 0 111 .byte 0, 0x92, 0x00, 0 112#else 113 .word 0xffff, 0 114 .byte 0, 0x92, 0x4f, 0 115#endif 116 117 /* 16 bit real mode, base will be patched */ 118bootrealseg = . - gdt 119 .word 0xffff, 0 120 .byte 0, 0x9e, 0x00, 0 121 122 /* limits (etc) for data segment in real mode */ 123bootrealdata = . - gdt 124 .word 0xffff, 0 125 .byte 0, 0x92, 0x00, 0 126gdtlen = . - gdt 127 128#ifdef __ELF__ 129 .align 16 130#else 131 .align 4 132#endif 133gdtarg: 134 .word gdtlen-1 /* limit */ 135 .long 0 /* addr, will be inserted */ 136 137 .text 138ENTRY(start) 139 .code16 140 141 # Check we are in real mode 142 movl %cr0, %eax 143 testl $CR0_PE, %eax 144 jz 2f 145 mov $1f, %si 146 call message 147 ret 1481: .asciz "must be in real mode\r\n" 1492: 150 151 xorl %eax, %eax 152 mov %cs, %ax 153 mov %ax, %ds 154 mov %ax, %es 155 movl %eax, _C_LABEL(ourseg) 156#ifdef STACK_START 157 add $STACK_START / 16, %ax 158 mov %ax, %ss 159 mov $0xfffc, %sp 160#endif 161 162 /* fix up GDT entries for bootstrap */ 163#define FIXUP(gdt_index) \ 164 movw %ax, gdt+gdt_index+2; \ 165 movb %bl, gdt+gdt_index+4 166 167 mov %cs, %ax 168 shll $4, %eax 169 shldl $16, %eax, %ebx 170 FIXUP(bootcodeseg) 171 FIXUP(bootrealseg) 172 FIXUP(bootdataseg) 173 174 /* fix up GDT pointer */ 175 addl $gdt, %eax 176 movl %eax, gdtarg+2 177 178 /* change to protected mode */ 179 calll _C_LABEL(real_to_prot) 180 .code32 181 182 /* clear the bss */ 183 movl $_C_LABEL(edata), %edi 184 movl $_C_LABEL(end), %ecx 185 subl %edi, %ecx 186 xorb %al, %al 187 rep 188 stosb 189 190 call _C_LABEL(doscommain) 191ENTRY(_rtt) 192 call _C_LABEL(prot_to_real) 193 .code16 194ENTRY(exit16) 195 sti 196 movb $0x4c, %ah /* return */ 197 int $0x21 198 199/* 200 * real_to_prot() 201 * transfer from real mode to protected mode. 202 */ 203ENTRY(real_to_prot) 204 .code16 205 pushl %eax 206 # guarantee that interrupt is disabled when in prot mode 207 cli 208 209 # load the gdtr 210 lgdtl %cs:gdtarg 211 212 # set the PE bit of CR0 213 movl %cr0, %eax 214 orl $CR0_PE, %eax 215 movl %eax, %cr0 216 217 # make intrasegment jump to flush the processor pipeline and 218 # reload CS register 219 ljmp $bootcodeseg, $xprot 220 221xprot: 222 .code32 223 # we are in USE32 mode now 224 # set up the protected mode segment registers : DS, SS, ES 225 movl $bootdataseg, %eax 226 mov %ax, %ds 227 mov %ax, %es 228 mov %ax, %ss 229#ifdef STACK_START 230 addl $STACK_START, %esp 231#endif 232 233 popl %eax 234 ret 235 236/* 237 * prot_to_real() 238 * transfer from protected mode to real mode 239 */ 240ENTRY(prot_to_real) 241 .code32 242 pushl %eax 243 # set up a dummy stack frame for the second seg change. 244 # Adjust the intersegment jump instruction following 245 # the clearing of protected mode bit. 246 # This is self-modifying code, but we need a writable 247 # code segment, and an intersegment return does not give us that. 248 249 movl _C_LABEL(ourseg), %eax 250 movw %ax, xreal-2 251 252 /* 253 * Load the segment registers while still in protected mode. 254 * Otherwise the control bits don't get changed. 255 * The correct values are loaded later. 256 */ 257 movw $bootrealdata, %ax 258 movw %ax, %ds 259 movw %ax, %es 260 movw %ax, %ss 261 262 # Change to use16 mode. 263 ljmp $bootrealseg, $x16 264 265x16: 266 .code16 267 # clear the PE bit of CR0 268 movl %cr0, %eax 269 andl $~CR0_PE, %eax 270 movl %eax, %cr0 271 272 # Here we have an 16 bits intersegment jump. 273 ljmp $0, $xreal /* segment patched above */ 274 275xreal: 276 # we are in real mode now 277 # set up the real mode segment registers : DS, SS, ES 278 mov %cs, %ax 279 mov %ax, %ds 280 mov %ax, %es 281#ifdef STACK_START 282 add $STACK_START / 16, %ax 283 mov %ax, %ss 284 subl $STACK_START, %esp 285#else 286 mov %ax, %ss 287#endif 288 push %bp 289 movw %sp, %bp 290 /* check we are returning to an address below 64k */ 291 movw 2/*bp*/ + 4/*eax*/ + 2(%bp), %ax /* high bits ret addr */ 292 test %ax, %ax 293 jne 1f 294 pop %bp 295 296 sti 297 popl %eax 298 retl 299 3001: movw $2f, %si 301 call message 302 movl 2/*bp*/ + 4/*eax*/(%bp), %eax /* return address */ 303 call dump_eax 304 jmp exit16 3052: .asciz "prot_to_real can't return to " 306 307 308/************************************************************************** 309___MAIN - Dummy to keep GCC happy 310**************************************************************************/ 311ENTRY(__main) 312 ret 313 314/* 315 * pbzero(dst, cnt) 316 * where dst is a physical address and cnt is the length 317 */ 318ENTRY(pbzero) 319 .code32 320 pushl %ebp 321 movl %esp, %ebp 322 pushl %es 323 pushl %edi 324 325 cld 326 327 # set %es to point at the flat segment 328 movl $flatdataseg, %eax 329 mov %ax, %es 330 331 movl 8(%ebp), %edi # destination 332 movl 12(%ebp), %ecx # count 333 xorl %eax, %eax # value 334 335 rep 336 stosb 337 338 popl %edi 339 popl %es 340 popl %ebp 341 ret 342 343/* 344 * vpbcopy(src, dst, cnt) 345 * where src is a virtual address and dst is a physical address 346 */ 347ENTRY(vpbcopy) 348 .code32 349 pushl %ebp 350 movl %esp, %ebp 351 pushl %es 352 pushl %esi 353 pushl %edi 354 355 cld 356 357 # set %es to point at the flat segment 358 movl $flatdataseg, %eax 359 mov %ax, %es 360 361 movl 8(%ebp), %esi # source 362 movl 12(%ebp), %edi # destination 363 movl 16(%ebp), %ecx # count 364 365 rep 366 movsb 367 368 popl %edi 369 popl %esi 370 popl %es 371 popl %ebp 372 ret 373 374/* 375 * pvbcopy(src, dst, cnt) 376 * where src is a physical address and dst is a virtual address 377 */ 378ENTRY(pvbcopy) 379 .code32 380 pushl %ebp 381 movl %esp, %ebp 382 pushl %ds 383 pushl %esi 384 pushl %edi 385 386 cld 387 388 # set %ds to point at the flat segment 389 movl $flatdataseg, %eax 390 mov %ax, %ds 391 392 movl 8(%ebp), %esi # source 393 movl 12(%ebp), %edi # destination 394 movl 16(%ebp), %ecx # count 395 396 rep 397 movsb 398 399 popl %edi 400 popl %esi 401 popl %ds 402 popl %ebp 403 ret 404 405ENTRY(vtophys) 406 .code32 407 movl _C_LABEL(ourseg), %eax 408 shll $4, %eax 409 addl 4(%esp), %eax 410 ret 411 412message: 413 .code16 414 pushal 415message_1: 416 cld 4171: lodsb 418 testb %al, %al 419 jz 2f 420 movb $0xe, %ah 421 movw $1, %bx 422 int $0x10 423 jmp 1b 424 4252: movb $0x86, %ah 426 mov $16, %cx 427 int $0x15 /* delay about a second */ 428 popal 429 ret 430 431/* These are useful for debugging 432 */ 433 .data 434eax_buf: 435 .long 0, 0, 0, 0 436 .text 437ENTRY(dump_eax) 438 .code16 439 pushal 440 movw $eax_buf, %si 441 mov %si, %di 442 movw $8, %cx 4431: roll $4, %eax 444 mov %ax, %bx 445 andb $0x0f, %al 446 addb $0x30, %al /* 30..3f - clear AF */ 447#if 1 /* 5 bytes to generate real hex... */ 448 daa /* 30..39, 40..45 */ 449 addb $0xc0, %al /* f0..f9, 00..05 */ 450 adcb $0x40, %al /* 30..39, 41..45 */ 451#endif 452 movb %al, (%di) /* %es != %ds, so can't ... */ 453 inc %di /* ... use stosb */ 454 mov %bx, %ax 455 loop 1b 456 movw $0x20, %ax /* space + null */ 457 movw %ax, (%di) 458 jmp message_1 459 460 .globl _C_LABEL(trace_word) 461_C_LABEL(trace_word): 462 .code32 463 movl 4(%esp), %edx 464 465 call _C_LABEL(prot_to_real) 466 .code16 467 movl %edx, %eax 468 call dump_eax 469 calll _C_LABEL(real_to_prot) 470 .code32 471 ret 472 473 .globl _C_LABEL(trace_str) 474_C_LABEL(trace_str): 475 .code32 476 pushl %esi 477 478 call _C_LABEL(prot_to_real) 479 .code16 480 mov %sp, %si 481 mov 8(%si), %si 482 call message 483 calll _C_LABEL(real_to_prot) 484 .code32 485 popl %esi 486 ret 487 488#ifdef XMS 489 490/* pointer to XMS driver, 0 if no XMS used */ 491 492 .data 493_C_LABEL(xmsdrv): 494 .long 0 495 496 .text 497ENTRY(checkxms) 498 .code32 499 pushl %ebp 500 movl %esp, %ebp 501 pushl %ebx 502 pushl %edx 503 pushl %es 504 pushl %esi 505 pushl %edi 506 507 call _C_LABEL(prot_to_real) # enter real mode 508 .code16 509 510 movw $0x4300, %ax 511 int $0x2f /* check if XMS installed */ 512 cmpb $0x80, %al 513 jnz noxms 514 515 movw $0x4310, %ax 516 int $0x2f /* get driver address */ 517 518 movw %bx, _C_LABEL(xmsdrv) /* save es:bx to _xmsdrv */ 519 movw %es, _C_LABEL(xmsdrv) + 2 520 521 movb $0x08, %ah /* XMS: query free extended memory */ 522#if 0 523 movb $0x00, %bl 524#endif 525 lcall *_C_LABEL(xmsdrv) 526 jmp xdone 527 528noxms: /* no XMS manager found */ 529 mov $0, %dx 530 531xdone: 532 calll _C_LABEL(real_to_prot) # back to protected mode 533 .code32 534 535 xorl %eax, %eax 536 movw %dx, %ax 537 538 popl %edi 539 popl %esi 540 popl %es 541 popl %edx 542 popl %ebx 543 popl %ebp 544 ret 545 546/* 547 Allocate a block of XMS memory with the requested size 548 void *xmsalloc(long int kBytes); 549 550 Depends on _xmsdrv being set by getextmem() before first call 551 to this function. 552 553 Return value: a physical address. 554*/ 555ENTRY(xmsalloc) 556 .code32 557 pushl %ebp 558 movl %esp, %ebp 559 pushl %ebx 560 pushl %edx 561 pushl %esi 562 pushl %edi 563 564 movl 0x8(%ebp), %edx # Kbytes needed 565 566 call _C_LABEL(prot_to_real) # enter real mode 567 .code16 568 569 movb $0x09, %ah # XMS allocate block 570 lcall *_C_LABEL(xmsdrv) # result: handle in %dx 571 movb $0x0c, %ah # XMS lock block 572 lcall *_C_LABEL(xmsdrv) # result: 32 bit physical addr in DX:BX 573 574 calll _C_LABEL(real_to_prot) # back to protected mode 575 .code32 576 577 movl %edx, %eax 578 shl $16, %eax 579 movw %bx, %ax # result in %eax 580 581 popl %edi 582 popl %esi 583 popl %edx 584 popl %ebx 585 popl %ebp 586 ret 587 588/* 589 * ppbcopy(src, dst, cnt) 590 * where src and dst are physical addresses 591 */ 592ENTRY(ppbcopy) 593 .code32 594 pushl %ebp 595 movl %esp, %ebp 596 pushl %es 597 pushl %esi 598 pushl %edi 599 600 cld 601 602 # set %es to point at the flat segment 603 movl $flatdataseg, %eax 604 mov %ax, %es 605 606 movl 8(%ebp), %esi # source 607 movl 12(%ebp), %edi # destination 608 movl 16(%ebp), %ecx # count 609 610 es 611 rep 612 movsb 613 614 popl %edi 615 popl %esi 616 popl %es 617 popl %ebp 618 ret 619 620#endif 621