|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/hal/x86/arch/locore.S/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /*- 2 * Copyright (c) 2005-2008, Kohsuke Ohtani 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * locore.S - low level platform support 32 */ 33 34 #include <conf/config.h> 35 #include <machine/asm.h> 36 #include <machine/syspage.h> 37 #include <machine/memory.h> 38 #include <sys/errno.h> 39 #include <cpu.h> 40 41 /* 42 * Macro to save/restore registers 43 * 44 * This macro builds the trap frame by pushing registers. 45 * If you change the push order of these macro, you must change the 46 * trap frame structure in arch.h. In addition, the system call stub 47 * will depend on this register format. 48 */ 49 #define SAVE_ALL \ 50 cld; \ 51 pushl %es; \ 52 pushl %ds; \ 53 pushl %ebp; \ 54 pushl %edi; \ 55 pushl %eax; \ 56 pushl %esi; \ 57 pushl %edx; \ 58 pushl %ecx; \ 59 pushl %ebx; 60 61 #define RESTORE_ALL \ 62 popl %ebx; \ 63 popl %ecx; \ 64 popl %edx; \ 65 popl %esi; \ 66 popl %eax; \ 67 popl %edi; \ 68 popl %ebp; \ 69 popl %ds; \ 70 popl %es; 71 72 #define SETUP_SEG \ 73 movl $(KERNEL_DS), %edx; \ 74 movl %edx, %ds; \ 75 movl %edx, %es; 76 77 .section ".text" 78 79 /* 80 * Kernel start point 81 * 82 * The kernel assumes that the following state is already set by 83 * the kernel loader. 84 * - CPU is in protected mode 85 * - Segment registers are set as 32-bit flat segment 86 * - A20 line is enabled for 32-bit addressing 87 * - Paging is turned off 88 * - The boot information is loaded to address 1000h-1fffh 89 */ 90 /* 91 * Note: The linker will generate an address for kernel_start as 0x80010000. 92 * But, the loader will load the kernel to 0x10000 (physical address). 93 * So, the linear address pointer can not be used until paging is enabled. 94 */ 95 ENTRY(kernel_start) 96 cli /* Disable interrupt */ 97 cld 98 99 /* 100 * Setup CPU registers. 101 */ 102 movl %cr0, %eax /* Enable kernel write protection */ 103 orl $(CR0_WP), %eax 104 movl %eax, %cr0 105 106 pushfl /* Clear nested task, iopl = 0 */ 107 popl %eax 108 andl $~(EFL_IOPL|EFL_NT), %eax 109 pushl %eax 110 popfl 111 112 #ifdef CONFIG_MMU 113 /* 114 * Initialize page table. 115 * The physical address 0-4M is mapped on virtual address 2G. 116 */ 117 movl $(BOOT_PGD_PHYS), %edi /* Setup kernel page directory */ 118 xorl %eax, %eax /* Invalidate all address */ 119 movl $0x1000, %ecx 120 rep 121 stosb 122 movl $(BOOT_PGD_PHYS+0x800), %edi 123 movl $(BOOT_PTE0_PHYS+0x07), (%edi) 124 movl $1024, %ecx /* Fill boot page table entry */ 125 movl $(BOOT_PTE0_PHYS), %edi 126 movl $0007, %eax 127 fill_pte0: 128 stosl 129 add $0x1000, %eax /* Process next page */ 130 loop fill_pte0 131 132 /* 133 * Enable paging. 134 * The physical address 0-4M is temporarily mapped to virtial 135 * address 0-4M. This is needed to enable paging. 136 */ 137 movl $(BOOT_PGD_PHYS), %edi /* Map address 0-4M */ 138 movl $(BOOT_PTE0_PHYS+0x07), (%edi) 139 movl $(BOOT_PGD_PHYS), %eax /* Set page directory pointer */ 140 movl %eax, %cr3 141 movl %cr0, %eax /* Enable paging bit */ 142 orl $(CR0_PG), %eax 143 movl %eax, %cr0 144 jmp pipeline_flush /* Flush processor pipeline */ 145 pipeline_flush: 146 movl $cs_reset, %eax 147 jmp *%eax 148 cs_reset: 149 movl $(BOOT_PGD), %edi /* Unmap 0-4M */ 150 movl $0, (%edi) 151 movl %cr3, %eax 152 movl %eax, %cr3 153 154 #endif /* CONFIG_MMU */ 155 156 /* 157 * Clear kernel BSS 158 */ 159 xorl %eax, %eax 160 movl $__bss, %edi 161 movl $__end, %ecx 162 subl %edi, %ecx 163 rep 164 stosb 165 166 /* 167 * Setup boot stack 168 */ 169 movl $(BOOTSTK), %edi 170 movl $(BOOTSTKSZ), %ecx 171 rep 172 stosb 173 movl $(BOOTSTKTOP), %esp 174 movl %esp, %ebp 175 176 movl $15, curspl 177 178 /* 179 * Call kernel main routine 180 */ 181 call main 182 /* NOTREACHED */ 183 cli 184 hlt 185 186 /* 187 * Common entry for all interrupts 188 * Setup interrupt stack for outermost interrupt. 189 * The code should be written to prevent the stack overflow 190 * by continuous interrupt as much as it can. 191 */ 192 ENTRY(interrupt_common) 193 SAVE_ALL 194 SETUP_SEG 195 incl irq_nesting /* Increment nesting level */ 196 cmpl $1, irq_nesting /* Outermost interrupt ? */ 197 jne nested_irq 198 mov %esp, %ebp /* Save current stack */ 199 movl $(INTSTKTOP), %esp /* Switch stack */ 200 call sched_lock /* Lock scheduler */ 201 pushl %ebp /* Push trap frame */ 202 call interrupt_handler /* Process interrupt */ 203 movl %ebp, %esp /* Restore original stack */ 204 decl irq_nesting 205 call sched_unlock /* Try to preempt */ 206 testl $3, 0x30(%esp) /* Return to kernel mode ? */ 207 jz interrupt_ret /* Skip exception if kernel mode */ 208 sti 209 call exception_deliver /* Check exception */ 210 interrupt_ret: 211 cli 212 RESTORE_ALL 213 addl $8, %esp 214 iret 215 nested_irq: 216 push %esp /* Push trap frame */ 217 call interrupt_handler /* Process interrupt */ 218 addl $4, %esp 219 decl irq_nesting 220 jmp interrupt_ret 221 222 /* 223 * Macro to build interrupt entry 224 */ 225 #define INTR_ENTRY(irq) \ 226 ENTRY(intr_##irq) \ 227 pushl $0; \ 228 pushl $(irq); \ 229 jmp interrupt_common 230 231 INTR_ENTRY(0) 232 INTR_ENTRY(1) 233 INTR_ENTRY(2) 234 INTR_ENTRY(3) 235 INTR_ENTRY(4) 236 INTR_ENTRY(5) 237 INTR_ENTRY(6) 238 INTR_ENTRY(7) 239 INTR_ENTRY(8) 240 INTR_ENTRY(9) 241 INTR_ENTRY(10) 242 INTR_ENTRY(11) 243 INTR_ENTRY(12) 244 INTR_ENTRY(13) 245 INTR_ENTRY(14) 246 INTR_ENTRY(15) 247 248 /* 249 * Common entry for all traps 250 * New thread will start from trap_ret. 251 */ 252 ENTRY(trap_common) 253 SAVE_ALL 254 SETUP_SEG 255 pushl %esp 256 call trap_handler 257 addl $4, %esp 258 trap_ret: 259 RESTORE_ALL 260 addl $8, %esp 261 iret 262 263 /* 264 * Default trap entry 265 */ 266 ENTRY(trap_default) 267 pushl $0 268 pushl $(INVALID_INT) 269 jmp trap_common 270 271 /* 272 * Macro to build trap entry 273 * Some trap will push the error code into stack. 274 */ 275 #define TRAP_ENTRY(id) \ 276 ENTRY(trap_##id) \ 277 pushl $0; \ 278 pushl $(id); \ 279 jmp trap_common; 280 281 #define TRAP_ERR_ENTRY(id) \ 282 ENTRY(trap_##id) \ 283 pushl $(id); \ 284 jmp trap_common; 285 286 TRAP_ENTRY ( 0) /* Divide error */ 287 TRAP_ENTRY ( 1) /* Debug trap */ 288 TRAP_ENTRY ( 2) /* NMI */ 289 TRAP_ENTRY ( 3) /* Breakpoint */ 290 TRAP_ENTRY ( 4) /* Overflow */ 291 TRAP_ENTRY ( 5) /* Bounds check */ 292 TRAP_ENTRY ( 6) /* Invalid opecode */ 293 TRAP_ENTRY ( 7) /* Device not available */ 294 TRAP_ERR_ENTRY( 8) /* Double fault */ 295 TRAP_ERR_ENTRY( 9) /* Coprocessor overrun */ 296 TRAP_ERR_ENTRY(10) /* Invalid TSS */ 297 TRAP_ERR_ENTRY(11) /* Segment not present */ 298 TRAP_ERR_ENTRY(12) /* Stack bounds */ 299 TRAP_ERR_ENTRY(13) /* General Protection */ 300 TRAP_ERR_ENTRY(14) /* Page fault */ 301 TRAP_ENTRY (15) /* (reserved) */ 302 TRAP_ENTRY (16) /* Coprocessor error */ 303 TRAP_ERR_ENTRY(17) /* Alignment check */ 304 TRAP_ERR_ENTRY(18) /* Cache flush denied */ 305 306 307 /* 308 * System call entry 309 */ 310 .global syscall_ret 311 ENTRY(syscall_entry) 312 pushl $0 /* Dummy for error code */ 313 pushl $(SYSCALL_INT) /* Trap number */ 314 SAVE_ALL 315 SETUP_SEG 316 call syscall_handler 317 cmpl $0, 0x10(%esp) /* Skip setting eax if exception_return */ 318 je 1f 319 movl %eax, 0x10(%esp) /* Set return value to eax */ 320 1: 321 call exception_deliver /* Check exception */ 322 syscall_ret: 323 RESTORE_ALL 324 addl $8, %esp /* Discard err/trap no */ 325 iret 326 327 /* 328 * Switch register context. 329 * Interrupts must be disabled by caller. 330 * 331 * syntax - void cpu_switch(kern_regs *prev, kern_regs *next) 332 * 333 * Note: GCC assumes ebx,ebp,edi,esi registers are not changed in each routine. 334 */ 335 ENTRY(cpu_switch) 336 movl 4(%esp), %ecx /* Point ecx to previous registers */ 337 movl (%esp), %eax /* Get return address */ 338 movl %eax, 0(%ecx) /* Save it as eip */ 339 movl %ebx, 4(%ecx) /* Save ebx */ 340 movl %edi, 8(%ecx) /* Save edi */ 341 movl %esi, 12(%ecx) /* Save esi */ 342 movl %ebp, 16(%ecx) /* Save ebp */ 343 movl %esp, 20(%ecx) /* Save esp */ 344 movl 8(%esp), %ecx /* Point ecx to next registers */ 345 movl 4(%ecx), %ebx /* Restore ebx */ 346 movl 8(%ecx), %edi /* Restore edi */ 347 movl 12(%ecx), %esi /* Restore esp */ 348 movl 16(%ecx), %ebp /* Restore ebp */ 349 movl 20(%ecx), %esp /* Restore esp */ 350 movl 0(%ecx), %eax /* Get eip */ 351 movl %eax, (%esp) /* Restore it as return address */ 352 ret 353 354 /* 355 * Copy data from user to kernel space. 356 * Returns 0 on success, or EFAULT on page fault. 357 * 358 * syntax - int copyin(const void *uaddr, void *kaddr, size_t len) 359 */ 360 .global known_fault1 361 ENTRY(copyin) 362 pushl %esi 363 pushl %edi 364 pushl $(EFAULT) /* Set EFAULT as default return */ 365 366 movl 16(%esp), %esi 367 movl 20(%esp), %edi 368 movl 24(%esp), %ecx 369 370 movl %esi, %edx /* Check if valid user address */ 371 addl %ecx, %edx 372 jc copy_fault 373 cmpl $(USERLIMIT), %edx /* User area? */ 374 jae copy_fault 375 cld 376 known_fault1: /* May be fault here */ 377 rep 378 movsb 379 380 popl %eax 381 xorl %eax, %eax /* Set no error */ 382 popl %edi 383 popl %esi 384 ret 385 386 /* 387 * Copy data to user from kernel space. 388 * Returns 0 on success, or EFAULT on page fault. 389 * 390 * syntax - int copyout(const void *kaddr, void *uaddr, size_t len) 391 */ 392 .global known_fault2 393 ENTRY(copyout) 394 pushl %esi 395 pushl %edi 396 pushl $(EFAULT) /* Set EFAULT as default return */ 397 398 movl 16(%esp), %esi 399 movl 20(%esp), %edi 400 movl 24(%esp), %ecx 401 402 movl %edi, %edx 403 addl %ecx, %edx 404 jc copy_fault 405 cmpl $(USERLIMIT), %edx /* User area? */ 406 jae copy_fault 407 cld 408 known_fault2: /* May be fault here */ 409 rep 410 movsb 411 412 popl %eax 413 xorl %eax, %eax /* Set no error */ 414 popl %edi 415 popl %esi 416 ret 417 418 /** 419 * copyinstr - Copy string from user space. 420 * Returns 0 on success, or EFAULT on page fault, or ENAMETOOLONG. 421 * 422 * syntax - int copyinstr(const char *uaddr, void *kaddr, size_t len); 423 * 424 * Note: The returned length value does NOT include the NULL terminator. 425 */ 426 .global known_fault3 427 ENTRY(copyinstr) 428 pushl %esi 429 pushl %edi 430 pushl $(EFAULT) /* Set EFAULT as default return */ 431 432 movl 16(%esp), %esi 433 movl 20(%esp), %edi 434 movl 24(%esp), %ecx 435 436 movl %esi, %edx /* Check if valid user address */ 437 addl %ecx, %edx 438 jc copy_fault 439 cmpl $(USERLIMIT), %edx /* User area? */ 440 jae copy_fault 441 cld 442 jmp 2f 443 1: 444 decl %ecx 445 jz copyin_toolong 446 2: 447 known_fault3: /* May be fault here */ 448 lodsb 449 stosb 450 testb %al, %al 451 jnz 1b 452 453 popl %eax 454 xorl %eax, %eax /* Set no error */ 455 popl %edi 456 popl %esi 457 ret 458 459 copyin_toolong: 460 popl %eax 461 movl $(ENAMETOOLONG), %eax 462 popl %edi 463 popl %esi 464 ret 465 466 /* 467 * Fault entry for user access 468 */ 469 ENTRY(copy_fault) 470 popl %eax /* Get return value from stack */ 471 popl %edi 472 popl %esi 473 ret 474 475 /* 476 * Reset cpu 477 * Use triple fault 478 */ 479 ENTRY(cpu_reset) 480 cli 481 movl $null_idt, %eax /* Reset by triple fault */ 482 lidt (%eax) 483 int $3 484 hlt 485 486 .align 4 487 null_idt: 488 .word 0 489 .long 0 490 491 /* 492 * Initialize cache. 493 */ 494 ENTRY(cache_init) 495 movl %cr0, %eax /* Clear cache disable bit */ 496 andl $~(CR0_CD), %eax 497 movl %eax, %cr0 498 ret 499 500 /* 501 * void splx(int s); 502 */ 503 ENTRY(splx) 504 cli 505 movl 4(%esp), %eax 506 movl %eax, curspl 507 cmpl $0, %eax 508 ja 1f 509 sti 510 1: 511 ret 512 513 /* 514 * int splhigh(void); 515 */ 516 ENTRY(splhigh) 517 cli 518 movl curspl, %eax 519 movl $15, curspl 520 ret 521 522 /* 523 * int spl0(void); 524 */ 525 ENTRY(spl0) 526 movl curspl, %eax 527 movl $0, curspl 528 sti 529 ret 530 531 /* 532 * Disable interrupts 533 */ 534 ENTRY(sploff) 535 cli 536 ret 537 538 /* 539 * Enable interrupts 540 */ 541 ENTRY(splon) 542 sti 543 ret 544 545 /* 546 * Interrupt nest counter. 547 * 548 * This counter is incremented in the entry of interrupt handler 549 * to switch the interrupt stack. Since all interrupt handlers 550 * share same one interrupt stack, each handler must pay attention 551 * to the stack overflow. 552 */ 553 .section ".bss" 554 irq_nesting: 555 .long 0 556 557 /* 558 * Current spl 559 */ 560 curspl: 561 .long 0 /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |