1/* $MirOS: src/sys/arch/i386/stand/libsa/gidt.S,v 1.31 2009/10/24 15:57:11 tg Exp $ */ 2/* $OpenBSD: gidt.S,v 1.32 2006/12/26 19:30:44 tom Exp $ */ 3 4/* 5 * Copyright (c) 2008, 2009 Thorsten Glaser 6 * Copyright (c) 1997 Michael Shalayeff 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 .file "gidt.S" 33 34#include <machine/asm.h> 35#define _LOCORE 36#include <machine/trap.h> 37#include <debug_md.h> 38#undef _LOCORE 39#include <assym.h> 40 41#include "gidt.h" 42 43 .globl _C_LABEL(BIOS_regs) 44 45 .text 46 .code32 47 48 .globl _C_LABEL(_rtt) 49ENTRY(_rtt) 50#ifdef GIDT_DEBUG 51 movl $0xb8000, %ebx 52 movl $0x4f514f51, (%ebx) 53#endif 54 movw $0x1234, %ax 55 movw %ax, 0x472 /* warm boot */ 56 57 /* Try to use the KBD to reboot system */ 58 movb $0xfe, %al 59 outb %al, $0x64 60 61 movl $0x5000, %ecx 621: inb $0x84, %al 63 loop 1b 64 65 movb $0xfe, %al 66 outb %al, $0x64 67 68#ifdef GIDT_DEBUG 69 movl $0xb8000, %ebx 70 movl $0x07310731, (%ebx) 71#endif 72 73 /* Try to cause a triple fault... */ 74 lidt Idtr_reset 75 xorl %eax, %eax 76 divl %eax, %eax 77 78 /* Again... */ 79 int $0x8 80 81 /* Again... */ 82 movl $0, %esp /* segment violation */ 83 ret 84 85 /* 86 * set up the protected mode Interrupt Descriptor Table 87 */ 88 89#ifdef __STDC__ 90#define IPROC(n) X##n 91#define IEMU(n) IPROC(emu##n) 92#define idtb(b) idte(emu##b) 93#else 94#define IPROC(n) X/**/n 95#define IEMU(n) IPROC(emu/**/n) 96#define idtb(b) idte(emu/**/b) 97#endif 98 99#define idte(e) \ 100 .long IPROC(e), ((S32TEXT) << 16) | ((0x80 | SDT_SYS386TGT) << 8) 101 102 .p2align 4 103 .globl idt_for_fixup 104idt_for_fixup: 105 idte(de); idte(db); idte(nmi); idte(bp); idte(of); idte(br) 106 idte(ud); idte(nm); idte(df); idte(fo); idte(ts); idte(np) 107 idte(ss); idte(gp); idte(pf); idte(xx); idte(mf); idte(ac) 108 idte(mc) 109 idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx) 110 idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx) 111 idte(xx) 112 /* Maskable interrupts (32-255) */ 113 /* BIOS entry points (32-63) */ 114 /* DOS entry points (64-80) */ 115 idtb(0); idtb(1); idtb(2); idtb(3); idtb(4); idtb(5) 116 idtb(6); idtb(7); idtb(8); idtb(9); idtb(10); idtb(11) 117 idtb(12); idtb(13); idtb(14); idtb(15); idtb(16); idtb(17) 118 idtb(18); idtb(19); idtb(20); idtb(21); idtb(22); idtb(23) 119 idtb(24); idtb(25); idtb(26); idtb(27); idtb(28); idtb(29) 120 idtb(30); idtb(31); idtb(32); idtb(33); idtb(34); idtb(35) 121 idtb(36); idtb(37); idtb(38); idtb(39); idtb(40); idtb(41) 122 idtb(42); idtb(43); idtb(44); idtb(45); idtb(46); idtb(47) 123 .globl idt_fixup_end 124idt_fixup_end: 125 126 .balign 8 127 .globl Idtr 128Idtr: .word idt_fixup_end - idt_for_fixup - 1 129 .long idt_for_fixup 130 .word 0 131 132 .balign 8 133 .globl Idtr_real 134Idtr_real: .word 1023 135 .long 0 136 .word 0 137 138 .balign 8 139Idtr_reset: .long 0, 0 140 141 .balign 8 142gdt: 143 /* 0x00 : null */ 144 .space 8 145 /* 0x08 : flat code */ 146 .word 0xFFFF # lolimit 147 .word 0 # lobase 148 .byte 0 # midbase 149 .byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present 150 .byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity 151 .byte 0 # hibase 152 /* 0x10 : flat data */ 153 .word 0xFFFF # lolimit 154 .word 0 # lobase 155 .byte 0 # midbase 156 .byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present 157 .byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity 158 .byte 0 # hibase 159 /* 0x18 : 16 bit code */ 160 .word 0xFFFF # lolimit 161 .word (SA_LINKADDR & 0xffff) # lobase 162 .byte (SA_LINKADDR >> 16) & 0xff # midbase 163 .byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present 164 .byte 0x0 | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity 165 .byte (SA_LINKADDR >> 20) & 0xff # hibase 166 /* 0x20 : 16 bit data */ 167 .word 0xFFFF # lolimit 168 .word (SA_LINKADDR & 0xffff) # lobase 169 .byte (SA_LINKADDR >> 16) & 0xff # midbase 170 .byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present 171 .byte 0x0 | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity 172 .byte (SA_LINKADDR >> 20) & 0xff # hibase 173 174.globl Gdtr 175Gdtr: .word . - gdt - 1 176 .long gdt 177 .word 0 178 179#define IENTRY(name,type) \ 180IPROC(name): \ 181 pushl $type ; \ 182 jmp 1f 183#define IENTRY_ERR(name,err,type) \ 184IPROC(name): \ 185 pushl $err ; \ 186 pushl $type ; \ 187 jmp 1f 188 189IPROC(xx): 190 pushl $1 191 pushl $T_RESERVED 192 jmp 1f 193 194IENTRY_ERR(de,0,T_DIVIDE) /* #DE divide by zero */ 195IENTRY_ERR(db,0,T_TRCTRAP) /* #DB debug */ 196IENTRY_ERR(nmi,0,T_NMI) /* NMI */ 197IENTRY_ERR(bp,0,T_BPTFLT) /* #BP breakpoint */ 198IENTRY_ERR(of,0,T_OFLOW) /* #OF overflow */ 199IENTRY_ERR(br,0,T_BOUND) /* #BR BOUND range exceeded */ 200IENTRY_ERR(ud,0,T_PRIVINFLT) /* #UD invalid opcode */ 201IENTRY_ERR(nm,0,T_DNA) /* #NM device not available */ 202IENTRY(df,T_DOUBLEFLT) /* #DF double fault */ 203IENTRY_ERR(fo,0,T_FPOPFLT) /* #FO coprocessor segment overrun */ 204IENTRY(ts,T_TSSFLT) /* #TS invalid TSS */ 205IENTRY(np,T_SEGNPFLT) /* #NP segment not present */ 206IENTRY(ss,T_STKFLT) /* #SS stack fault */ 207IENTRY(gp,T_PROTFLT) /* #GP general protection */ 208IENTRY(pf,T_PAGEFLT) /* #PF page fault */ 209IENTRY_ERR(mf,0,T_ARITHTRAP) /* #MF floating point error */ 210IENTRY(ac,T_ALIGNFLT) /* #AC alignment check */ 211IENTRY(mc,T_MACHK) /* #MC machine check */ 212 213 .globl alltraps 2141: /* save on jumps */ 215 jmp alltraps 216 217#define IEMUENT(n) IEMU(n): pushl $n; jmp 1f 218 219IEMUENT(0); IEMUENT(1); IEMUENT(2); IEMUENT(3) 220IEMUENT(4); IEMUENT(5); IEMUENT(6); IEMUENT(7) 221IEMUENT(8); IEMUENT(9); IEMUENT(10); IEMUENT(11) 222IEMUENT(12); IEMUENT(13); IEMUENT(14); IEMUENT(15) 223IEMUENT(16); IEMUENT(17); IEMUENT(18); IEMUENT(19) 224IEMUENT(20); IEMUENT(21); IEMUENT(22); IEMUENT(23) 225IEMUENT(24); IEMUENT(25); IEMUENT(26); IEMUENT(27) 226IEMUENT(28); IEMUENT(29); IEMUENT(30); IEMUENT(31) 2271: jmp EMUh /* redirect for short jumps */ 228IEMUENT(32); IEMUENT(33); IEMUENT(34); IEMUENT(35) 229IEMUENT(36); IEMUENT(37); IEMUENT(38); IEMUENT(39) 230IEMUENT(40); IEMUENT(41); IEMUENT(42); IEMUENT(43) 231IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47) 2321: jmp EMUh 233 234/* 235 * entry point for BIOS real-mode interface 236 * all the magic for real-prot mode switching is here 237 * 238 * Call: %eax, %ecx, %edx, %ebx, %ebp, %esi, %edi, %es, %ds 239 * Return: %eax, %edx, %ecx, %eflags (as returned from BIOS) 240 * 241 */ 242 .globl EMUh 243 .balign 8, 0x90 244 .intel_syntax noprefix 245EMUh: 246 xchg [esp],eax 247 mov [LemuNR],al 248 pop eax 249 250 push ebx 251 push ebp 252 push esi 253 push edi 254 push ds 255 push es 256 push fs 257 push gs 258 259 push eax 260 mov eax,[BIOS_regs + BIOSR_DS] 261 push eax 262 mov eax,[BIOS_regs + BIOSR_ES] 263 push eax 264 265 call prot_to_real 266 .code16 267 268 pop eax 269 mov es,ax 270 pop eax 271 mov ds,ax 272 pop eax 273 274 sti 275 int 0 276 LemuNR = . - 1 277 cli 278 279 push eax 280 lahf 281 push eax 282 xor eax,eax 283 mov ax,es 284 push eax 285 286 call real_to_prot 287 .code32 288 289 mov [BIOS_regs + BIOSR_CX],ecx 290 mov [BIOS_regs + BIOSR_DX],edx 291 mov [BIOS_regs + BIOSR_BX],ebx 292 mov [BIOS_regs + BIOSR_BP],ebp 293 mov [BIOS_regs + BIOSR_SI],esi 294 mov [BIOS_regs + BIOSR_DI],edi 295 pop eax 296 mov [BIOS_regs + BIOSR_ES],eax 297 pop ebx 298 pop eax 299 mov [BIOS_regs + BIOSR_AX],eax 300 301 pushfd 302 pop ebp 303 and ebp,0xFFFFBFFF /* clear NT flag */ 304 push ebp 305 popfd 306 307 pop gs 308 pop fs 309 pop es 310 pop ds 311 pop edi 312 pop esi 313 pop ebp 314 mov [esp+12],bh 315 pop ebx 316 iret 317 318#ifndef SMALL_BOOT 319/* Return to DOS or SYSLINUX */ 320ENTRY(rtdos) 321 call prot_to_real 322 .code16 323 mov ax,0x4C00 324 int 0x21 3251: jmp 1b 326 .code32 327/* Call buffer at 07c0:0000 in real mode to simulate a BIOS boot */ 328ENTRY(bootbuf) 329 pop eax /* Don't need return address */ 330 pop esi /* Buffer Source (linear) */ 331 pop ecx /* Size */ 332 pop ebp /* Buffer Target (ES:DI) */ 333 pop ebx /* Device and flags */ 334 pop edi /* Initial CS:IP */ 335 336 xor edx,edx 337 dec edx /* EDX = 0xFFFFFFFF */ 338 mov dl,bl /* EDX = 0xFFFFFFzz (z = device) */ 339 340 call prot_to_real 341 .code16 342 343 /* set up flags, real mode stack */ 344 xor eax,eax 345 mov ss,ax 346 mov esp,0x000006F0 347 push eax 348 popf 349 350 /*- 351 * Now the machine status is as follows: 352 * - CS = DS = ES = 4000h = (SA_LINKSEG) 353 * - SS:SP = 0000:06F0h (to make room for !PXE ptr) 354 * - EFLAGS = 0 355 * - ESI = linear address of source buffer (must be para aligned) 356 * - ECX = source buffer size (up to 64 KiB) 357 * - EBP = target address as ES:DI (FAR pointer) 358 * - EDI = initial CS:IP (FAR pointer) 359 * - EBX = bootbuf flags, currently unused 360 * - EDX = drive 361 * - _C_LABEL(bios_bootpte) = future DS:SI contents (16by) 362 * - 0000:0600h .. 0000:07FFh are available to put the boot 363 * partition table entry in, according to SYSLINUX docs; 364 * we also move certain relocation code there, and our 365 * stack is also positioned in there 366 * - we assume ECX > (“ES”<<4)|“DI” [EBP] 367 * - “DI” is almost certainly 0 and should be 368 */ 369 370 mov eax,edi 371 shr eax,16 372 push ax /* future CS */ 373 push di /* future IP */ 374 mov eax,ds:[8] 375 push eax /* !PXE structure RM address */ 376 mov eax,ds:[12] 377 push eax /* PXENV+ structure RM address */ 378 push edx /* future DL (drive) */ 379 push ecx /* source buffer size */ 380 shr esi,4 381 push si /* source buffer segment */ 382 mov eax,ebp 383 shr eax,16 384 push ax /* buffer ES */ 385 push bp /* buffer DI */ 386 xor ecx,ecx 387 mov es,cx 388 mov edi,0x0600 389 mov esi,offset _C_LABEL(bios_bootpte) - SA_LINKADDR 390 mov cx,4 391 rep movsd 392 push es /* temporary CS */ 393 push di /* temporary IP */ 394 call Ltcend 395Ltcbeg: /* temporary relocation code, copied to 0000:0610h */ 396 pop di /* buffer target (DI) */ 397 pop es /* buffer target (ES) */ 398 pop ds /* source buffer segment */ 399Ltcbig: pop ecx /* source buffer size */ 400 xor si,si /* source buffer offset */ 401 cmp ecx,0x00010000 402 jb Ltcseg 403 /* copy 64 KiB, reduce, retry */ 404 sub ecx,0x00010000 405 push ecx 406 mov ecx,0x4000 /* 64 KiB in dwords */ 407 push di 408 rep movsd 409 pop di 410 mov ax,ds 411 add ax,0x1000 412 mov ds,ax 413 mov ax,es 414 add ax,0x1000 415 mov es,ax 416 jmp Ltcbig 417Ltcseg: rep movsb 418Ltcrun: xor ax,ax 419 mov ds,ax 420 mov si,0x0600 421 pop edx /* drive */ 422 pop bx /* PXENV+ offset */ 423 pop es /* PXENV+ segment */ 424 pop edi /* !PXE */ 425 mov bp,sp 426 mov [bp+8],edi 427 lret /* future CS:IP on stack */ 428Ltcend: pop si /* offset Ltcbeg */ 429 mov cx,offset Ltcend - offset Ltcbeg 430 rep movsb 431 lret /* temporary CS:IP (0000:0610h) on stack */ 432#endif 433 434/*- 435 * Switch from protected mode to real mode. 436 * Registers trashed: EAX 437 * CS = DS = ES = SA_LINKSEG 438 * SS:SP = old flat:ESP 439 */ 440 .code32 441 .globl prot_to_real 442prot_to_real: 443 cli 444 /* switch to 16 bit code size */ 445 ljmp S16TEXT,offset Lp2r32 - SA_LINKADDR 446Lp2r32: .code16 447 mov ax,S16DATA 448 mov ds,ax 449 mov es,ax 450 mov fs,ax 451 mov gs,ax 452 mov ss,ax 453 /* disable protected mode */ 454 mov eax,cr0 455 and eax,~CR0_PE 456 mov cr0,eax 457 /* switch to 16 bit data size */ 458 data32 ljmp SA_LINKSEG,offset Lp2r16 - SA_LINKADDR 459Lp2r16: /* convert ESP to SS:SP */ 460 mov eax,esp 461 shr eax,4 462 and ax,0xF000 463 mov ss,ax 464 and esp,0x0000FFFF 465 /* load real mode segments */ 466 mov ax,cs 467 mov ds,ax 468 mov es,ax 469 mov fs,ax 470 mov gs,ax 471 /* load real mode IDT */ 472 data32 addr32 lidt (Idtr_real - SA_LINKADDR) 473 /* fix up return address */ 474 pop eax 475 sub eax,SA_LINKADDR 476 push ax 477 ret 478 479/*- 480 * Switch from real mode to protected mode. 481 * Registers trashed: EAX 482 * CS = S32TEXT 483 * DS = ES = SS = S32DATA 484 * ESP = flat, old (SS<<4)|SP 485 */ 486 .code16 487 .globl real_to_prot 488real_to_prot: 489 cli 490 /* fix up return address */ 491 xor eax,eax 492 pop ax 493 add eax,SA_LINKADDR 494 push eax 495 /* load GDT via data segment */ 496 mov ax,SA_LINKSEG 497 mov ds,ax 498 data32 addr32 lgdt (Gdtr - SA_LINKADDR) 499 /* convert SS:SP to ESP */ 500 xor eax,eax 501 mov ax,ss 502 shl eax,4 503 and esp,0x0000FFFF 504 add esp,eax 505 /* enter protected mode */ 506 mov eax,cr0 507 or eax,CR0_PE 508 mov cr0,eax 509 /* switch to 32 bit */ 510 data32 ljmp S32TEXT,offset Lr2p32 511Lr2p32: .code32 512 mov eax,S32DATA 513 mov ds,ax 514 mov es,ax 515 mov fs,ax 516 mov gs,ax 517 mov ss,ax 518 /* load protected mode IDT */ 519 lidt Idtr 520 ret 521