1/* $OpenBSD: gidt.S,v 1.37 2019/11/09 17:58:48 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 1997 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 .file "gidt.S" 31 32#include <machine/asm.h> 33#define _LOCORE 34#include <machine/trap.h> 35#include <debug_md.h> 36#undef _LOCORE 37#include <assym.h> 38 39#include "gidt.h" 40 41#ifdef GIDT_DEBUG 42#define gidt_debug0 ; \ 43 mov $0xb8000, %eax ; \ 44 mov $0x47314730, (%eax) 45#define gidt_debug1 ; \ 46 mov $(0xb8000 - LINKADDR), %eax ; \ 47 mov $0x4f314f30, (%eax) 48#define gidt_debug2 ; \ 49 mov $0xb8004, %eax ; \ 50 mov $0x47334732, (%eax) 51#define gidt_debug3 ; \ 52 mov $0xb8004, %eax ; \ 53 mov $0x4f334f32, (%eax) 54#define gidt_debug4 ; \ 55 movl $0xb8008, %eax ; \ 56 movl $0x47344733, (%eax) 57#else 58#define gidt_debug0 /* gidt_debug0 */ 59#define gidt_debug1 /* gidt_debug1 */ 60#define gidt_debug2 /* gidt_debug2 */ 61#define gidt_debug3 /* gidt_debug3 */ 62#define gidt_debug4 /* gidt_debug4 */ 63#endif 64 65#define prot2real \ 66 gidt_debug0; \ 67 \ 68 ljmp $S16TEXT, $1f - LINKADDR; \ 691: \ 70 .code16; \ 71 movw $S16DATA, %ax; \ 72 movw %ax, %ds; \ 73 movw %ax, %es; \ 74 gidt_debug1; \ 75 \ 76 movl %cr0, %eax; /* disable pmmm */ \ 77 andl $~CR0_PE, %eax; \ 78 movl %eax, %cr0; \ 79 \ 80 /* reload real cs:ip */ \ 81 data32 ljmp $(LINKADDR >> 4), $1f - LINKADDR; \ 821: \ 83 movw %cs, %ax; /* setup: %ds, %es, %ss = %cs */ \ 84 movw %ax, %ds; \ 85 movw %ax, %es; \ 86 xorw %ax, %ax; \ 87 movw %ax, %ss; \ 88 \ 89 gidt_debug2; \ 90 \ 91 data32 addr32 lidt (Idtr_real - LINKADDR); /* load idtr for real mode */ 92 93#define real2prot \ 94 gidt_debug3; \ 95 \ 96 movw $LINKADDR >> 4, %ax; \ 97 movw %ax, %ds; \ 98 data32 addr32 lgdt (Gdtr - LINKADDR); /* load the gdtr */ \ 99 \ 100 movl %cr0, %eax; /* enable pmmm */ \ 101 orl $CR0_PE, %eax; \ 102 movl %eax, %cr0; \ 103 \ 104 data32 ljmp $S32TEXT, $1f; /* reload %cs,flush pipeline */\ 1051: \ 106 .code32; \ 107 /* reload 32bit %ds, %ss, %es */ \ 108 mov $S32DATA, %eax; \ 109 mov %ax, %ds; \ 110 mov %ax, %ss; \ 111 mov %ax, %es; \ 112 \ 113 gidt_debug4; \ 114 \ 115 /* load idtr for debugger and DOS/BIOS iface */ \ 116 lidt Idtr; 117 118 119 .globl _C_LABEL(BIOS_regs) 120 121 .text 122 .code32 123 .globl _ASM_LABEL(pmm_init) 124 .globl _C_LABEL(_rtt) 125 126ENTRY(_rtt) 127#ifdef SOFTRAID 128 call _C_LABEL(sr_clear_keys) 129#endif 130#ifdef GIDT_DEBUG 131 movl $0xb8000, %ebx 132 movl $0x4f514f51, (%ebx) 133#endif 134 movw $0x1234, %ax 135 movw %ax, 0x472 /* warm boot */ 136 137 /* Try to use the KBD to reboot system */ 138 movb $0xfe, %al 139 outb %al, $0x64 140 141 movl $0x5000, %ecx 1421: inb $0x84, %al 143 loop 1b 144 145 movb $0xfe, %al 146 outb %al, $0x64 147 148#ifdef GIDT_DEBUG 149 movl $0xb8000, %ebx 150 movl $0x07310731, (%ebx) 151#endif 152 153 /* Try to cause a triple fault... */ 154 lidt Idtr_reset 155 xorl %eax, %eax 156 divl %eax, %eax 157 158 /* Again... */ 159 int $0x8 160 161 /* Again... */ 162 movl $0, %esp /* segment violation */ 163 ret 164 165#define IPROC(n) X##n 166#define IEMU(n) IPROC(emu##n) 167 168create_idt_entry: 169 movw %ax, (%ebx) 170 movw $S32TEXT, 2(%ebx) 171 movw $((0x80|SDT_SYS386TGT) << 8), 4(%ebx) 172 shr $16, %eax 173 movw %ax, 6(%ebx) 174 addl $8, %ebx 175 ret 176 177 .align 8, 0x90 178pmm_init: 179 180#define idte(e) \ 181 movl $IPROC(e), %eax; call create_idt_entry 182#define idtb(b) idte(emu##b) 183 184 /* Build interrupt descriptor table. */ 185 /* Maskable interrupts (32-255) */ 186 movl $idt, %ebx 187 movl $Idtr, %eax 188 movw $(640 - 1), (%eax) 189 movl %ebx, 2(%eax) 190 191 /* Internal (0-31) */ 192 idte(de); idte(db); idte(nmi); idte(bp); idte(of); idte(br) 193 idte(ud); idte(nm); idte(df); idte(fo); idte(ts); idte(np) 194 idte(ss); idte(gp); idte(pf); idte(xx); idte(mf); idte(ac) 195 idte(mc) 196 idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx) 197 idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx) 198 idte(xx) 199 /* BIOS entry points (32-63) */ 200 idtb(0); idtb(1); idtb(2); idtb(3); idtb(4); idtb(5) 201 idtb(6); idtb(7); idtb(8); idtb(9); idtb(10); idtb(11) 202 idtb(12); idtb(13); idtb(14); idtb(15); idtb(16); idtb(17) 203 idtb(18); idtb(19); idtb(20); idtb(21); idtb(22); idtb(23) 204 idtb(24); idtb(25); idtb(26); idtb(27); idtb(28); idtb(29) 205 idtb(30); idtb(31); idtb(32); idtb(33); idtb(34); idtb(35) 206 idtb(36); idtb(37); idtb(38); idtb(39); idtb(40); idtb(41) 207 idtb(42); idtb(43); idtb(44); idtb(45); idtb(46); idtb(47) 208 /* DOS entry points (64-80) */ 209 210#undef idtb 211#undef idte 212 213 /* load idtr for interrupts */ 214 lidt Idtr 215 ret 216 217 .bss 218 .align 8, 0x90 219idt: 220 /* IDT has 80 entries at 8 bytes each. */ 221 .space 640 222 223 .globl Idtr 224Idtr: .word 0 // 640 - 1 225 .long 0 // idt 226 .word 0 227 228 .text 229 .align 8 230 .globl Idtr_real 231Idtr_real: 232 .word 1023 233 .long 0 234 .word 0 235 236 .align 8 237Idtr_reset: 238 .long 0, 0 239 240 .align 8 241gdt: 242 /* 0x00 : null */ 243 .space 8 244 /* 0x08 : flat code */ 245 .word 0xFFFF # lolimit 246 .word 0 # lobase 247 .byte 0 # midbase 248 .byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present 249 .byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity 250 .byte 0 # hibase 251 /* 0x10 : flat data */ 252 .word 0xFFFF # lolimit 253 .word 0 # lobase 254 .byte 0 # midbase 255 .byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present 256 .byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity 257 .byte 0 # hibase 258 /* 0x18 : 16 bit code */ 259 .word 0xFFFF # lolimit 260 .word (LINKADDR & 0xffff) # lobase 261 .byte (LINKADDR >> 16) & 0xff # midbase 262 .byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present 263 .byte 0x0 | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity 264 .byte (LINKADDR >> 20) & 0xff # hibase 265 /* 0x20 : 16 bit data */ 266 .word 0xFFFF # lolimit 267 .word (LINKADDR & 0xffff) # lobase 268 .byte (LINKADDR >> 16) & 0xff # midbase 269 .byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present 270 .byte 0x0 | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity 271 .byte (LINKADDR >> 20) & 0xff # hibase 272 273.globl Gdtr 274Gdtr: .word . - gdt - 1 275 .long gdt 276 .word 0 277 278#define IENTRY(name,type) \ 279IPROC(name): \ 280 pushl $type ; \ 281 jmp 1f 282#define IENTRY_ERR(name,err,type) \ 283IPROC(name): \ 284 pushl $err ; \ 285 pushl $type ; \ 286 jmp 1f 287 288IPROC(xx): 289 pushl $1 290 pushl $T_RESERVED 291 jmp 1f 292 293IENTRY_ERR(de,0,T_DIVIDE) /* #DE divide by zero */ 294IENTRY_ERR(db,0,T_TRCTRAP) /* #DB debug */ 295IENTRY_ERR(nmi,0,T_NMI) /* NMI */ 296IENTRY_ERR(bp,0,T_BPTFLT) /* #BP breakpoint */ 297IENTRY_ERR(of,0,T_OFLOW) /* #OF overflow */ 298IENTRY_ERR(br,0,T_BOUND) /* #BR BOUND range exceeded */ 299IENTRY_ERR(ud,0,T_PRIVINFLT) /* #UD invalid opcode */ 300IENTRY_ERR(nm,0,T_DNA) /* #NM device not available */ 301IENTRY(df,T_DOUBLEFLT) /* #DF double fault */ 302IENTRY_ERR(fo,0,T_FPOPFLT) /* #FO coprocessor segment overrun */ 303IENTRY(ts,T_TSSFLT) /* #TS invalid TSS */ 304IENTRY(np,T_SEGNPFLT) /* #NP segment not present */ 305IENTRY(ss,T_STKFLT) /* #SS stack fault */ 306IENTRY(gp,T_PROTFLT) /* #GP general protection */ 307IENTRY(pf,T_PAGEFLT) /* #PF page fault */ 308IENTRY_ERR(mf,0,T_ARITHTRAP) /* #MF floating point error */ 309IENTRY(ac,T_ALIGNFLT) /* #AC alignment check */ 310IENTRY(mc,T_MACHK) /* #MC machine check */ 311 312 .globl alltraps 3131: /* save on jumps */ 314 jmp alltraps 315 316#define IEMUENT(n) IEMU(n): pushl $n; jmp 1f 317 318IEMUENT(0); IEMUENT(1); IEMUENT(2); IEMUENT(3) 319IEMUENT(4); IEMUENT(5); IEMUENT(6); IEMUENT(7) 320IEMUENT(8); IEMUENT(9); IEMUENT(10); IEMUENT(11) 321IEMUENT(12); IEMUENT(13); IEMUENT(14); IEMUENT(15) 322IEMUENT(16); IEMUENT(17); IEMUENT(18); IEMUENT(19) 323IEMUENT(20); IEMUENT(21); IEMUENT(22); IEMUENT(23) 324IEMUENT(24); IEMUENT(25); IEMUENT(26); IEMUENT(27) 325IEMUENT(28); IEMUENT(29); IEMUENT(30); IEMUENT(31) 3261: jmp EMUh /* redirect for short jumps */ 327IEMUENT(32); IEMUENT(33); IEMUENT(34); IEMUENT(35) 328IEMUENT(36); IEMUENT(37); IEMUENT(38); IEMUENT(39) 329IEMUENT(40); IEMUENT(41); IEMUENT(42); IEMUENT(43) 330IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47) 3311: jmp EMUh 332 333/* 334 * entry point for BIOS real-mode interface 335 * all the magic for real-prot mode switching is here 336 * 337 * Note: Once in real mode access to .data or .bss should be avoided since it 338 * may not be reachable within the current segment. The following code also 339 * assumes that .text is writeable. 340 * 341 * Call: %eax, %ecx, %edx, %ebx, %ebp, %esi, %edi, %es, %ds 342 * Return: %eax, %edx, %ecx, %eflags (as returned from BIOS) 343 * 344 */ 345 .globl EMUh 346 .align 8, 0x90 347EMUh: 348 /* save %eax */ 349 mov %eax, 5f 350 pop %eax 351 352 pusha 353 push %ds 354 push %es 355 push %fs 356 push %gs 357 358 /* save BIOS int vector */ 359 mov %al, intno 360 361 /* Load BIOS registers prior to switching to real mode. */ 362 movl _C_LABEL(BIOS_regs)+BIOSR_ES, %eax 363 mov %eax, 7f 364 movl _C_LABEL(BIOS_regs)+BIOSR_DS, %eax 365 mov %eax, 6f 366 367 prot2real 368 369 push %ds 370 371 # data32 movl $Leax, %eax 372 .byte 0x66, 0xb8 3737: .long 0x90909090 374 mov %ax, %es 375 376 # data32 movl $Leax, %eax 377 .byte 0x66, 0xb8 3786: .long 0x90909090 379 mov %ax, %ds 380 381 # data32 movl $Leax, %eax 382 .byte 0x66, 0xb8 3835: .long 0x90909090 384 385 ;sti 386 int $0 387intno = . - 1 388 ;cli 389 390 pop %ds 391 392 /* Preserve BX and ES for protected mode. */ 393 addr32 movl %eax, (2f - LINKADDR) 394 movl %ebx, %eax 395 addr32 movl %eax, (4f - LINKADDR) 396 movl %es, %eax 397 addr32 movl %eax, (3f - LINKADDR) 398 addr32 movl (2f - LINKADDR), %eax 399 400 movb %ah, %bh 401 lahf 402 xchgb %ah, %bh 403 404 /* Preserve AX for protected mode. */ 405 addr32 movl %eax, (2f - LINKADDR) 406 407 real2prot 408 409 # movl $Leax, %eax 410 .byte 0xb8 4114: .long 0x90909090 412 movl %eax, _C_LABEL(BIOS_regs)+BIOSR_BX 413 414 # movl $Leax, %eax 415 .byte 0xb8 4163: .long 0x90909090 417 movl %eax, _C_LABEL(BIOS_regs)+BIOSR_ES 418 419 # movl $Leax, %eax 420 .byte 0xb8 4212: .long 0x90909090 422 423 /* pass BIOS return values back to caller */ 424 movl %eax, 0xb*4(%esp) 425 movl %ecx, 0xa*4(%esp) 426 movl %edx, 0x9*4(%esp) 427 movb %bh , 0xe*4(%esp) 428 429 /* save registers into save area */ 430 movl %eax, _C_LABEL(BIOS_regs)+BIOSR_AX 431 movl %ecx, _C_LABEL(BIOS_regs)+BIOSR_CX 432 movl %edx, _C_LABEL(BIOS_regs)+BIOSR_DX 433 movl %ebp, _C_LABEL(BIOS_regs)+BIOSR_BP 434 movl %esi, _C_LABEL(BIOS_regs)+BIOSR_SI 435 movl %edi, _C_LABEL(BIOS_regs)+BIOSR_DI 436 437 /* clear NT flag in eflags */ 438 pushf 439 pop %eax 440 and $0xffffbfff, %eax 441 push %eax 442 popf 443 444 pop %gs 445 pop %fs 446 pop %es 447 pop %ds 448 popa 449 iret 450 451/* Call buffer at 07c0:0000 in real mode to simulate a BIOS boot */ 452ENTRY(bootbuf) 453 pop %eax /* Don't need return address */ 454 pop %esi /* Buffer */ 455 pop %edx /* Device */ 456 prot2real /* Switch */ 457 458 /* Set up stack */ 459 cli 460 xor %ax, %ax 461 mov %ax, %ss 462 mov $0xfffc, %esp 463 sti 464 465 /* Jump to buffer */ 466 ljmp $0x0, $0x7c00 467 468 .end 469