Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/hal/x86/arch/locore.S

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kernel_start
  2. interrupt_common
  3. trap_common
  4. trap_default
  5. syscall_entry
  6. cpu_switch
  7. copyin
  8. copyout
  9. copyinstr
  10. copy_fault
  11. cpu_reset
  12. cache_init
  13. splx
  14. splhigh
  15. spl0
  16. sploff
  17. splon

   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] */