1 /* $NetBSD: start_dos.S,v 1.2 2024/09/11 20:15:36 andvar 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 */ 10 11 /* 12 * Ported to boot 386BSD by Julian Elischer (julian (at) tfs.com) Sept 1992 13 * 14 * Mach Operating System 15 * Copyright (c) 1992, 1991 Carnegie Mellon University 16 * All Rights Reserved. 17 * 18 * Permission to use, copy, modify and distribute this software and its 19 * documentation is hereby granted, provided that both the copyright 20 * notice and this permission notice appear in all copies of the 21 * software, derivative works or modified versions, and any portions 22 * thereof, and that both notices appear in supporting documentation. 23 * 24 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 25 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 26 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27 * 28 * Carnegie Mellon requests users of this software to return to 29 * 30 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 31 * School of Computer Science 32 * Carnegie Mellon University 33 * Pittsburgh PA 15213-3890 34 * 35 * any improvements or extensions that they make and grant Carnegie Mellon 36 * the rights to redistribute these changes. 37 */ 38 39 /* 40 Copyright 1988, 1989, 1990, 1991, 1992 41 by Intel Corporation, Santa Clara, California. 42 43 All Rights Reserved 44 45 Permission to use, copy, modify, and distribute this software and 46 its documentation for any purpose and without fee is hereby 47 granted, provided that the above copyright notice appears in all 48 copies and that both the copyright notice and this permission notice 49 appear in supporting documentation, and that the name of Intel 50 not be used in advertising or publicity pertaining to distribution 51 of the software without specific, written prior permission. 52 53 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 54 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 55 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 56 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 57 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 58 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 59 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 60 */ 61 62 #include <machine/asm.h> 63 64 65 CR0_PE = 0x1 66 67 .data 68 .globl _C_LABEL(ourseg) 69 _C_LABEL(ourseg): 70 .long 0 71 72 /************************************************************************** 73 GLOBAL DESCRIPTOR TABLE 74 **************************************************************************/ 75 #ifdef __ELF__ 76 .align 16 77 #else 78 .align 4 79 #endif 80 gdt: 81 .word 0, 0 82 .byte 0, 0x00, 0x00, 0 83 84 #ifdef SUPPORT_LINUX /* additional dummy */ 85 .word 0, 0 86 .byte 0, 0x00, 0x00, 0 87 #endif 88 89 /* kernel code segment */ 90 .globl flatcodeseg 91 flatcodeseg = . - gdt 92 .word 0xffff, 0 93 .byte 0, 0x9f, 0xcf, 0 94 95 /* kernel data segment */ 96 .globl flatdataseg 97 flatdataseg = . - gdt 98 .word 0xffff, 0 99 .byte 0, 0x93, 0xcf, 0 100 101 /* boot code segment, base will be patched */ 102 bootcodeseg = . - gdt 103 .word 0xffff, 0 104 .byte 0, 0x9e, 0x40, 0 105 106 /* boot data segment, base will be patched */ 107 bootdataseg = . - gdt 108 #ifdef HEAP_BELOW_64K 109 .word 0xffff, 0 110 .byte 0, 0x92, 0x00, 0 111 #else 112 .word 0xffff, 0 113 .byte 0, 0x92, 0x4f, 0 114 #endif 115 116 /* 16 bit real mode, base will be patched */ 117 bootrealseg = . - gdt 118 .word 0xffff, 0 119 .byte 0, 0x9e, 0x00, 0 120 121 /* limits (etc) for data segment in real mode */ 122 bootrealdata = . - gdt 123 .word 0xffff, 0 124 .byte 0, 0x92, 0x00, 0 125 gdtlen = . - gdt 126 127 #ifdef __ELF__ 128 .align 16 129 #else 130 .align 4 131 #endif 132 gdtarg: 133 .word gdtlen-1 /* limit */ 134 .long 0 /* addr, will be inserted */ 135 136 .text 137 ENTRY(start) 138 .code16 139 140 # Check we are in real mode 141 movl %cr0, %eax 142 testl $CR0_PE, %eax 143 jz 2f 144 mov $1f, %si 145 call message 146 ret 147 1: .asciz "must be in real mode\r\n" 148 2: 149 150 xorl %eax, %eax 151 mov %cs, %ax 152 mov %ax, %ds 153 mov %ax, %es 154 movl %eax, _C_LABEL(ourseg) 155 #ifdef STACK_START 156 add $STACK_START / 16, %ax 157 mov %ax, %ss 158 mov $0xfffc, %sp 159 #endif 160 161 /* fix up GDT entries for bootstrap */ 162 #define FIXUP(gdt_index) \ 163 movw %ax, gdt+gdt_index+2; \ 164 movb %bl, gdt+gdt_index+4 165 166 mov %cs, %ax 167 shll $4, %eax 168 shldl $16, %eax, %ebx 169 FIXUP(bootcodeseg) 170 FIXUP(bootrealseg) 171 FIXUP(bootdataseg) 172 173 /* fix up GDT pointer */ 174 addl $gdt, %eax 175 movl %eax, gdtarg+2 176 177 /* change to protected mode */ 178 calll _C_LABEL(real_to_prot) 179 .code32 180 181 /* clear the bss */ 182 movl $_C_LABEL(edata), %edi 183 movl $_C_LABEL(end), %ecx 184 subl %edi, %ecx 185 xorb %al, %al 186 rep 187 stosb 188 189 call _C_LABEL(doscommain) 190 ENTRY(_rtt) 191 call _C_LABEL(prot_to_real) 192 .code16 193 ENTRY(exit16) 194 sti 195 movb $0x4c, %ah /* return */ 196 int $0x21 197 198 /* 199 * real_to_prot() 200 * transfer from real mode to protected mode. 201 */ 202 ENTRY(real_to_prot) 203 .code16 204 pushl %eax 205 # guarantee that interrupt is disabled when in prot mode 206 cli 207 208 # load the gdtr 209 lgdtl %cs:gdtarg 210 211 # set the PE bit of CR0 212 movl %cr0, %eax 213 orl $CR0_PE, %eax 214 movl %eax, %cr0 215 216 # make intrasegment jump to flush the processor pipeline and 217 # reload CS register 218 ljmp $bootcodeseg, $xprot 219 220 xprot: 221 .code32 222 # we are in USE32 mode now 223 # set up the protected mode segment registers : DS, SS, ES 224 movl $bootdataseg, %eax 225 mov %ax, %ds 226 mov %ax, %es 227 mov %ax, %ss 228 #ifdef STACK_START 229 addl $STACK_START, %esp 230 #endif 231 232 popl %eax 233 ret 234 235 /* 236 * prot_to_real() 237 * transfer from protected mode to real mode 238 */ 239 ENTRY(prot_to_real) 240 .code32 241 pushl %eax 242 # set up a dummy stack frame for the second seg change. 243 # Adjust the intersegment jump instruction following 244 # the clearing of protected mode bit. 245 # This is self-modifying code, but we need a writable 246 # code segment, and an intersegment return does not give us that. 247 248 movl _C_LABEL(ourseg), %eax 249 movw %ax, xreal-2 250 251 /* 252 * Load the segment registers while still in protected mode. 253 * Otherwise the control bits don't get changed. 254 * The correct values are loaded later. 255 */ 256 movw $bootrealdata, %ax 257 movw %ax, %ds 258 movw %ax, %es 259 movw %ax, %ss 260 261 # Change to use16 mode. 262 ljmp $bootrealseg, $x16 263 264 x16: 265 .code16 266 # clear the PE bit of CR0 267 movl %cr0, %eax 268 andl $~CR0_PE, %eax 269 movl %eax, %cr0 270 271 # Here we have an 16 bits intersegment jump. 272 ljmp $0, $xreal /* segment patched above */ 273 274 xreal: 275 # we are in real mode now 276 # set up the real mode segment registers : DS, SS, ES 277 mov %cs, %ax 278 mov %ax, %ds 279 mov %ax, %es 280 #ifdef STACK_START 281 add $STACK_START / 16, %ax 282 mov %ax, %ss 283 subl $STACK_START, %esp 284 #else 285 mov %ax, %ss 286 #endif 287 push %bp 288 movw %sp, %bp 289 /* check we are returning to an address below 64k */ 290 movw 2/*bp*/ + 4/*eax*/ + 2(%bp), %ax /* high bits ret addr */ 291 test %ax, %ax 292 jne 1f 293 pop %bp 294 295 sti 296 popl %eax 297 retl 298 299 1: movw $2f, %si 300 call message 301 movl 2/*bp*/ + 4/*eax*/(%bp), %eax /* return address */ 302 call dump_eax 303 jmp exit16 304 2: .asciz "prot_to_real can't return to " 305 306 307 /************************************************************************** 308 ___MAIN - Dummy to keep GCC happy 309 **************************************************************************/ 310 ENTRY(__main) 311 ret 312 313 /* 314 * pbzero(dst, cnt) 315 * where dst is a physical address and cnt is the length 316 */ 317 ENTRY(pbzero) 318 .code32 319 pushl %ebp 320 movl %esp, %ebp 321 pushl %es 322 pushl %edi 323 324 cld 325 326 # set %es to point at the flat segment 327 movl $flatdataseg, %eax 328 mov %ax, %es 329 330 movl 8(%ebp), %edi # destination 331 movl 12(%ebp), %ecx # count 332 xorl %eax, %eax # value 333 334 rep 335 stosb 336 337 popl %edi 338 popl %es 339 popl %ebp 340 ret 341 342 /* 343 * vpbcopy(src, dst, cnt) 344 * where src is a virtual address and dst is a physical address 345 */ 346 ENTRY(vpbcopy) 347 .code32 348 pushl %ebp 349 movl %esp, %ebp 350 pushl %es 351 pushl %esi 352 pushl %edi 353 354 cld 355 356 # set %es to point at the flat segment 357 movl $flatdataseg, %eax 358 mov %ax, %es 359 360 movl 8(%ebp), %esi # source 361 movl 12(%ebp), %edi # destination 362 movl 16(%ebp), %ecx # count 363 364 rep 365 movsb 366 367 popl %edi 368 popl %esi 369 popl %es 370 popl %ebp 371 ret 372 373 /* 374 * pvbcopy(src, dst, cnt) 375 * where src is a physical address and dst is a virtual address 376 */ 377 ENTRY(pvbcopy) 378 .code32 379 pushl %ebp 380 movl %esp, %ebp 381 pushl %ds 382 pushl %esi 383 pushl %edi 384 385 cld 386 387 # set %ds to point at the flat segment 388 movl $flatdataseg, %eax 389 mov %ax, %ds 390 391 movl 8(%ebp), %esi # source 392 movl 12(%ebp), %edi # destination 393 movl 16(%ebp), %ecx # count 394 395 rep 396 movsb 397 398 popl %edi 399 popl %esi 400 popl %ds 401 popl %ebp 402 ret 403 404 ENTRY(vtophys) 405 .code32 406 movl _C_LABEL(ourseg), %eax 407 shll $4, %eax 408 addl 4(%esp), %eax 409 ret 410 411 message: 412 .code16 413 pushal 414 message_1: 415 cld 416 1: lodsb 417 testb %al, %al 418 jz 2f 419 movb $0xe, %ah 420 movw $1, %bx 421 int $0x10 422 jmp 1b 423 424 2: movb $0x86, %ah 425 mov $16, %cx 426 int $0x15 /* delay about a second */ 427 popal 428 ret 429 430 /* These are useful for debugging 431 */ 432 .data 433 eax_buf: 434 .long 0, 0, 0, 0 435 .text 436 ENTRY(dump_eax) 437 .code16 438 pushal 439 movw $eax_buf, %si 440 mov %si, %di 441 movw $8, %cx 442 1: roll $4, %eax 443 mov %ax, %bx 444 andb $0x0f, %al 445 addb $0x30, %al /* 30..3f - clear AF */ 446 #if 1 /* 5 bytes to generate real hex... */ 447 daa /* 30..39, 40..45 */ 448 addb $0xc0, %al /* f0..f9, 00..05 */ 449 adcb $0x40, %al /* 30..39, 41..45 */ 450 #endif 451 movb %al, (%di) /* %es != %ds, so can't ... */ 452 inc %di /* ... use stosb */ 453 mov %bx, %ax 454 loop 1b 455 movw $0x20, %ax /* space + null */ 456 movw %ax, (%di) 457 jmp message_1 458 459 .globl _C_LABEL(trace_word) 460 _C_LABEL(trace_word): 461 .code32 462 movl 4(%esp), %edx 463 464 call _C_LABEL(prot_to_real) 465 .code16 466 movl %edx, %eax 467 call dump_eax 468 calll _C_LABEL(real_to_prot) 469 .code32 470 ret 471 472 .globl _C_LABEL(trace_str) 473 _C_LABEL(trace_str): 474 .code32 475 pushl %esi 476 477 call _C_LABEL(prot_to_real) 478 .code16 479 mov %sp, %si 480 mov 8(%si), %si 481 call message 482 calll _C_LABEL(real_to_prot) 483 .code32 484 popl %esi 485 ret 486