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