Changeset 89c57b6 in mainline for kernel/arch/ia32/src/asm.S


Ignore:
Timestamp:
2011-04-13T14:45:41Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
88634420
Parents:
cefb126 (diff), 17279ead (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/ia32/src/asm.S

    rcefb126 r89c57b6  
    11/*
    2  * Copyright (c) 2001 Jakub Jermar
     2 * Copyright (c) 2010 Jakub Jermar
    33 * All rights reserved.
    44 *
     
    3131 */
    3232
    33 /**
    34  * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
    35  * has no error word  and 1 means interrupt with error word
    36  *
    37  */
    38 #define ERROR_WORD_INTERRUPT_LIST  0x00027d00
    39 
    4033#include <arch/pm.h>
     34#include <arch/cpu.h>
    4135#include <arch/mm/page.h>
    4236
     
    4438.global paging_on
    4539.global enable_l_apic_in_msr
    46 .global interrupt_handlers
    47 .global memsetb
    48 .global memsetw
    49 .global memcpy
    5040.global memcpy_from_uspace
    5141.global memcpy_from_uspace_failover_address
     
    5444.global early_putchar
    5545
    56 /* Wrapper for generic memsetb */
    57 memsetb:
    58         jmp _memsetb
    59 
    60 /* Wrapper for generic memsetw */
    61 memsetw:
    62         jmp _memsetw
    63 
    6446#define MEMCPY_DST   4
    6547#define MEMCPY_SRC   8
     
    8163 *
    8264 */
    83 memcpy:
    8465memcpy_from_uspace:
    8566memcpy_to_uspace:
     
    155136        ret
    156137
    157 /** Clear nested flag
    158  *
    159  */
    160 .macro CLEAR_NT_FLAG
    161         pushfl
    162         andl $0xffffbfff, (%esp)
    163         popfl
    164 .endm
    165 
    166 /*
    167  * The SYSENTER syscall mechanism can be used for syscalls with
    168  * four or fewer arguments. To pass these four arguments, we
    169  * use four registers: EDX, ECX, EBX, ESI. The syscall number
    170  * is passed in EAX. We use EDI to remember the return address
    171  * and EBP to remember the stack. The INT-based syscall mechanism
    172  * can actually handle six arguments plus the syscall number
    173  * entirely in registers.
    174  */
    175 .global sysenter_handler
    176 sysenter_handler:
    177         sti
    178         pushl %ebp  /* remember user stack */
    179         pushl %edi  /* remember return user address */
    180        
    181         xorl %ebp, %ebp  /* stop stack traces here */
    182        
    183         pushl %gs  /* remember TLS */
    184        
    185         pushl %eax     /* syscall number */
    186         subl $8, %esp  /* unused sixth and fifth argument */
    187         pushl %esi     /* fourth argument */
    188         pushl %ebx     /* third argument */
    189         pushl %ecx     /* second argument */
    190         pushl %edx     /* first argument */
    191        
    192         movw $16, %ax
    193         movw %ax, %ds
    194         movw %ax, %es
    195        
    196         cld
    197         call syscall_handler
    198         addl $28, %esp  /* remove arguments from stack */
    199        
    200         pop %gs  /* restore TLS */
    201        
    202         pop %edx  /* prepare return EIP for SYSEXIT */
    203         pop %ecx  /* prepare userspace ESP for SYSEXIT */
    204        
    205         sysexit   /* return to userspace */
    206 
    207 #define ISTATE_OFFSET_EAX         0
    208 #define ISTATE_OFFSET_EBX         4
    209 #define ISTATE_OFFSET_ECX         8
    210 #define ISTATE_OFFSET_EDX         12
    211 #define ISTATE_OFFSET_EDI         16
    212 #define ISTATE_OFFSET_ESI         20
    213 #define ISTATE_OFFSET_EBP         24
     138#define ISTATE_OFFSET_EDX         0
     139#define ISTATE_OFFSET_ECX         4
     140#define ISTATE_OFFSET_EBX         8
     141#define ISTATE_OFFSET_ESI         12
     142#define ISTATE_OFFSET_EDI         16
     143#define ISTATE_OFFSET_EBP         20
     144#define ISTATE_OFFSET_EAX         24
    214145#define ISTATE_OFFSET_EBP_FRAME   28
    215146#define ISTATE_OFFSET_EIP_FRAME   32
     
    231162#define ISTATE_SOFT_SIZE  52
    232163
    233 /** Declare interrupt handlers
    234  *
    235  * Declare interrupt handlers for n interrupt
    236  * vectors starting at vector i.
    237  *
    238  * The handlers setup data segment registers
    239  * and call exc_dispatch().
    240  *
    241  */
    242 #define INTERRUPT_ALIGN  256
    243 
    244 .macro handler i n
    245         .ifeq \i - 0x30
    246                 /* Syscall handler */
    247                 pushl %ds
    248                 pushl %es
    249                 pushl %fs
    250                 pushl %gs
    251                
    252                 /*
    253                  * Push syscall arguments onto the stack
    254                  *
    255                  * NOTE: The idea behind the order of arguments passed
    256                  *       in registers is to use all scratch registers
    257                  *       first and preserved registers next. An optimized
    258                  *       libc syscall wrapper can make use of this setup.
    259                  *
    260                  */
    261                 pushl %eax
    262                 pushl %ebp
    263                 pushl %edi
    264                 pushl %esi
    265                 pushl %ebx
    266                 pushl %ecx
    267                 pushl %edx
    268                
    269                 /* We must fill the data segment registers */
    270                 movw $16, %ax
    271                 movw %ax, %ds
    272                 movw %ax, %es
    273                
    274                 xorl %ebp, %ebp
    275                
    276                 cld
    277                 sti
    278                
    279                 /* Call syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax) */
    280                 call syscall_handler
    281                 cli
    282                
    283                 movl 20(%esp), %ebp  /* restore EBP */
    284                 addl $28, %esp       /* clean-up of parameters */
    285                
    286                 popl %gs
    287                 popl %fs
    288                 popl %es
    289                 popl %ds
    290                
    291                 CLEAR_NT_FLAG
    292                 iret
     164/*
     165 * The SYSENTER syscall mechanism can be used for syscalls with
     166 * four or fewer arguments. To pass these four arguments, we
     167 * use four registers: EDX, ECX, EBX, ESI. The syscall number
     168 * is passed in EAX. We use EDI to remember the return address
     169 * and EBP to remember the stack. The INT-based syscall mechanism
     170 * can actually handle six arguments plus the syscall number
     171 * entirely in registers.
     172 */
     173.global sysenter_handler
     174sysenter_handler:
     175
     176        /*
     177         * Note that the space needed for the istate structure has been
     178         * preallocated on the stack by before_thread_runs_arch().
     179         */
     180
     181        /*
     182         * Save the return address and the userspace stack in the istate
     183         * structure on locations that would normally be taken by them.
     184         */
     185        movl %ebp, ISTATE_OFFSET_ESP(%esp)
     186        movl %edi, ISTATE_OFFSET_EIP(%esp)
     187
     188        /*
     189         * Push syscall arguments onto the stack
     190         */
     191        movl %eax, ISTATE_OFFSET_EAX(%esp)
     192        movl %ebx, ISTATE_OFFSET_EBX(%esp)
     193        movl %ecx, ISTATE_OFFSET_ECX(%esp)
     194        movl %edx, ISTATE_OFFSET_EDX(%esp)
     195        movl %esi, ISTATE_OFFSET_ESI(%esp)
     196        movl %edi, ISTATE_OFFSET_EDI(%esp)      /* observability; not needed */
     197        movl %ebp, ISTATE_OFFSET_EBP(%esp)      /* observability; not needed */
     198       
     199        /*
     200         * Fake up the stack trace linkage.
     201         */
     202        movl %edi, ISTATE_OFFSET_EIP_FRAME(%esp)
     203        movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
     204        leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
     205
     206        /*
     207         * Save TLS.
     208         */
     209        movl %gs, %edx
     210        movl %edx, ISTATE_OFFSET_GS(%esp)
     211
     212        /*
     213         * Switch to kernel selectors.
     214         */
     215        movw $(GDT_SELECTOR(KDATA_DES)), %ax
     216        movw %ax, %ds
     217        movw %ax, %es
     218       
     219        /*
     220         * Sanitize EFLAGS.
     221         *
     222         * SYSENTER does not clear the NT flag, which could thus proliferate
     223         * from here to the IRET instruction via a context switch and result
     224         * in crash.
     225         *
     226         * SYSENTER does not clear DF, which the ABI assumes to be cleared.
     227         *
     228         * SYSENTER clears IF, which we would like to be set for syscalls.
     229         *
     230         */
     231        pushl $(EFLAGS_IF)  /* specify EFLAGS bits that we want to set */
     232        popfl               /* set bits from the mask, clear or ignore others */
     233
     234        call syscall_handler
     235       
     236        /*
     237         * Restore TLS.
     238         */
     239        movl ISTATE_OFFSET_GS(%esp), %edx
     240        movl %edx, %gs
     241       
     242        /*
     243         * Prepare return address and userspace stack for SYSEXIT.
     244         */
     245        movl ISTATE_OFFSET_EIP(%esp), %edx
     246        movl ISTATE_OFFSET_ESP(%esp), %ecx
     247
     248        sysexit   /* return to userspace */
     249
     250/*
     251 * This is the legacy syscall handler using the interrupt mechanism.
     252 */
     253.global int_syscall
     254int_syscall:
     255        subl $(ISTATE_SOFT_SIZE + 4), %esp
     256
     257        /*
     258         * Push syscall arguments onto the stack
     259         *
     260         * NOTE: The idea behind the order of arguments passed
     261         *       in registers is to use all scratch registers
     262         *       first and preserved registers next. An optimized
     263         *       libc syscall wrapper can make use of this setup.
     264         *       The istate structure is arranged in the way to support
     265         *       this idea.
     266         *
     267         */
     268        movl %eax, ISTATE_OFFSET_EAX(%esp)
     269        movl %ebx, ISTATE_OFFSET_EBX(%esp)
     270        movl %ecx, ISTATE_OFFSET_ECX(%esp)
     271        movl %edx, ISTATE_OFFSET_EDX(%esp)
     272        movl %edi, ISTATE_OFFSET_EDI(%esp)
     273        movl %esi, ISTATE_OFFSET_ESI(%esp)
     274        movl %ebp, ISTATE_OFFSET_EBP(%esp)
     275
     276        /*
     277         * Save the selector registers.
     278         */
     279        movl %gs, %ecx
     280        movl %fs, %edx
     281
     282        movl %ecx, ISTATE_OFFSET_GS(%esp)
     283        movl %edx, ISTATE_OFFSET_FS(%esp)
     284
     285        movl %es, %ecx
     286        movl %ds, %edx
     287               
     288        movl %ecx, ISTATE_OFFSET_ES(%esp)
     289        movl %edx, ISTATE_OFFSET_DS(%esp)
     290
     291        /*
     292         * Switch to kernel selectors.
     293         */
     294        movl $(GDT_SELECTOR(KDATA_DES)), %eax
     295        movl %eax, %ds
     296        movl %eax, %es
     297               
     298        movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
     299        movl ISTATE_OFFSET_EIP(%esp), %eax
     300        movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
     301        leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
     302               
     303        cld
     304               
     305        /* Call syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax) */
     306        call syscall_handler
     307                       
     308        /*
     309         * Restore the selector registers.
     310         */
     311        movl ISTATE_OFFSET_GS(%esp), %ecx
     312        movl ISTATE_OFFSET_FS(%esp), %edx
     313
     314        movl %ecx, %gs
     315        movl %edx, %fs
     316
     317        movl ISTATE_OFFSET_ES(%esp), %ecx
     318        movl ISTATE_OFFSET_DS(%esp), %edx
     319                       
     320        movl %ecx, %es
     321        movl %edx, %ds
     322                       
     323        /*
     324         * Restore the preserved registers the handler cloberred itself
     325         * (i.e. EBP).
     326         */
     327        movl ISTATE_OFFSET_EBP(%esp), %ebp
     328                       
     329        addl $(ISTATE_SOFT_SIZE + 4), %esp
     330        iret
     331               
     332/**
     333 * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
     334 * has no error word  and 1 means interrupt with error word
     335 *
     336 */
     337#define ERROR_WORD_INTERRUPT_LIST  0x00027d00
     338
     339.macro handler i
     340.global int_\i
     341int_\i:
     342        /*
     343         * This macro distinguishes between two versions of ia32
     344         * exceptions. One version has error word and the other
     345         * does not have it. The latter version fakes the error
     346         * word on the stack so that the handlers and istate_t
     347         * can be the same for both types.
     348         */
     349        .iflt \i - 32
     350                .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
     351                        /*
     352                         * Exception with error word.
     353                         */
     354                        subl $ISTATE_SOFT_SIZE, %esp
     355                .else
     356                        /*
     357                         * Exception without error word: fake up one
     358                         */
     359                        subl $(ISTATE_SOFT_SIZE + 4), %esp
     360                .endif
    293361        .else
    294362                /*
    295                  * This macro distinguishes between two versions of ia32
    296                  * exceptions. One version has error word and the other
    297                  * does not have it. The latter version fakes the error
    298                  * word on the stack so that the handlers and istate_t
    299                  * can be the same for both types.
     363                 * Interrupt: fake up an error word
    300364                 */
    301                 .iflt \i - 32
    302                         .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
    303                                 /*
    304                                  * Exception with error word: do nothing
    305                                  */
    306                         .else
    307                                 /*
    308                                  * Exception without error word: fake up one
    309                                  */
    310                                 pushl $0
    311                         .endif
    312                 .else
    313                         /*
    314                          * Interrupt: fake up one
    315                          */
    316                         pushl $0
    317                 .endif
    318                
    319                 subl $ISTATE_SOFT_SIZE, %esp
    320                
    321                 /*
    322                  * Save the general purpose registers.
    323                  */
    324                 movl %eax, ISTATE_OFFSET_EAX(%esp)
    325                 movl %ebx, ISTATE_OFFSET_EBX(%esp)
    326                 movl %ecx, ISTATE_OFFSET_ECX(%esp)
    327                 movl %edx, ISTATE_OFFSET_EDX(%esp)
    328                 movl %edi, ISTATE_OFFSET_EDI(%esp)
    329                 movl %esi, ISTATE_OFFSET_ESI(%esp)
    330                 movl %ebp, ISTATE_OFFSET_EBP(%esp)
    331                
    332                 /*
    333                  * Save the selector registers.
    334                  */
    335                 movl %gs, %eax
    336                 movl %fs, %ebx
    337                 movl %es, %ecx
    338                 movl %ds, %edx
    339                
    340                 movl %eax, ISTATE_OFFSET_GS(%esp)
    341                 movl %ebx, ISTATE_OFFSET_FS(%esp)
    342                 movl %ecx, ISTATE_OFFSET_ES(%esp)
    343                 movl %edx, ISTATE_OFFSET_DS(%esp)
    344                
    345                 /*
    346                  * Switch to kernel selectors.
    347                  */
    348                 movl $16, %eax
    349                 movl %eax, %ds
    350                 movl %eax, %es
    351                
    352                 /*
    353                  * Imitate a regular stack frame linkage.
    354                  * Stop stack traces here if we came from userspace.
    355                  */
    356                 cmpl $8, ISTATE_OFFSET_CS(%esp)
    357                 jz 0f
    358                 xorl %ebp, %ebp
    359                
    360                 0:
    361                
    362                         movl %ebp, ISTATE_OFFSET_EBP_FRAME(%esp)
    363                         movl ISTATE_OFFSET_EIP(%esp), %eax
    364                         movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
    365                         leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
    366                        
    367                         cld
    368                        
    369                         pushl %esp   /* pass istate address */
    370                         pushl $(\i)  /* pass intnum */
    371                        
    372                         /* Call exc_dispatch(intnum, istate) */
    373                         call exc_dispatch
    374                        
    375                         addl $8, %esp  /* clear arguments from the stack */
    376                        
    377                         CLEAR_NT_FLAG
    378                        
    379                         /*
    380                          * Restore the selector registers.
    381                          */
    382                         movl ISTATE_OFFSET_GS(%esp), %eax
    383                         movl ISTATE_OFFSET_FS(%esp), %ebx
    384                         movl ISTATE_OFFSET_ES(%esp), %ecx
    385                         movl ISTATE_OFFSET_DS(%esp), %edx
    386                        
    387                         movl %eax, %gs
    388                         movl %ebx, %fs
    389                         movl %ecx, %es
    390                         movl %edx, %ds
    391                        
    392                         /*
    393                          * Restore the scratch registers and the preserved
    394                          * registers the handler cloberred itself
    395                          * (i.e. EBX and EBP).
    396                          */
    397                         movl ISTATE_OFFSET_EAX(%esp), %eax
    398                         movl ISTATE_OFFSET_EBX(%esp), %ebx
    399                         movl ISTATE_OFFSET_ECX(%esp), %ecx
    400                         movl ISTATE_OFFSET_EDX(%esp), %edx
    401                         movl ISTATE_OFFSET_EBP(%esp), %ebp
    402                        
    403                         addl $(ISTATE_SOFT_SIZE + 4), %esp
    404                         iret
    405                
     365                subl $(ISTATE_SOFT_SIZE + 4), %esp
    406366        .endif
    407367       
    408         .align INTERRUPT_ALIGN
    409         .if (\n - \i) - 1
    410                 handler "(\i + 1)", \n
    411         .endif
     368        /*
     369         * Save the general purpose registers.
     370         */
     371        movl %eax, ISTATE_OFFSET_EAX(%esp)
     372        movl %ebx, ISTATE_OFFSET_EBX(%esp)
     373        movl %ecx, ISTATE_OFFSET_ECX(%esp)
     374        movl %edx, ISTATE_OFFSET_EDX(%esp)
     375        movl %edi, ISTATE_OFFSET_EDI(%esp)
     376        movl %esi, ISTATE_OFFSET_ESI(%esp)
     377        movl %ebp, ISTATE_OFFSET_EBP(%esp)
     378       
     379        /*
     380         * Save the selector registers.
     381         */
     382        movl %gs, %ecx
     383        movl %fs, %edx
     384
     385        movl %ecx, ISTATE_OFFSET_GS(%esp)
     386        movl %edx, ISTATE_OFFSET_FS(%esp)
     387
     388        movl %es, %ecx
     389        movl %ds, %edx
     390       
     391        movl %ecx, ISTATE_OFFSET_ES(%esp)
     392        movl %edx, ISTATE_OFFSET_DS(%esp)
     393       
     394        /*
     395         * Switch to kernel selectors.
     396         */
     397        movl $(GDT_SELECTOR(KDATA_DES)), %eax
     398        movl %eax, %ds
     399        movl %eax, %es
     400       
     401        /*
     402         * Imitate a regular stack frame linkage.
     403         * Stop stack traces here if we came from userspace.
     404         */
     405        xorl %eax, %eax
     406        cmpl $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%esp)
     407        cmovnzl %eax, %ebp
     408
     409        movl %ebp, ISTATE_OFFSET_EBP_FRAME(%esp)
     410        movl ISTATE_OFFSET_EIP(%esp), %eax
     411        movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
     412        leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
     413               
     414        cld
     415               
     416        pushl %esp   /* pass istate address */
     417        pushl $(\i)  /* pass intnum */
     418               
     419        /* Call exc_dispatch(intnum, istate) */
     420        call exc_dispatch
     421               
     422        addl $8, %esp  /* clear arguments from the stack */
     423               
     424        /*
     425         * Restore the selector registers.
     426         */
     427        movl ISTATE_OFFSET_GS(%esp), %ecx
     428        movl ISTATE_OFFSET_FS(%esp), %edx
     429
     430        movl %ecx, %gs
     431        movl %edx, %fs
     432
     433        movl ISTATE_OFFSET_ES(%esp), %ecx
     434        movl ISTATE_OFFSET_DS(%esp), %edx
     435               
     436        movl %ecx, %es
     437        movl %edx, %ds
     438               
     439        /*
     440         * Restore the scratch registers and the preserved
     441         * registers the handler cloberred itself
     442         * (i.e. EBP).
     443         */
     444        movl ISTATE_OFFSET_EAX(%esp), %eax
     445        movl ISTATE_OFFSET_ECX(%esp), %ecx
     446        movl ISTATE_OFFSET_EDX(%esp), %edx
     447        movl ISTATE_OFFSET_EBP(%esp), %ebp
     448               
     449        addl $(ISTATE_SOFT_SIZE + 4), %esp
     450        iret
    412451.endm
    413452
    414 /* Keep in sync with pm.h! */
    415 #define IDT_ITEMS  64
    416 
    417 .align INTERRUPT_ALIGN
     453#define LIST_0_63 \
     454        0, 1, 2, 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,\
     455        28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,\
     456        53,54,55,56,57,58,59,60,61,62,63
     457
    418458interrupt_handlers:
    419         h_start:
    420                 handler 0 IDT_ITEMS
    421         h_end:
     459.irp cnt, LIST_0_63
     460        handler \cnt
     461.endr
    422462
    423463/** Print Unicode character to EGA display.
     
    428468 * Since the EGA can only display Extended ASCII (usually
    429469 * ISO Latin 1) characters, some of the Unicode characters
    430  * can be displayed in a wrong way. Only the newline character
    431  * is interpreted, all other characters (even unprintable) are
     470 * can be displayed in a wrong way. Only newline and backspace
     471 * are interpreted, all other characters (even unprintable) are
    432472 * printed verbatim.
    433473 *
     
    481521       
    482522        cmp $0x0a, %al
    483         jne early_putchar_print
     523        jne early_putchar_backspace
    484524       
    485525                /* Interpret newline */
     
    495535                subw %dx, %bx
    496536               
    497                 jmp early_putchar_newline
     537                jmp early_putchar_skip
     538       
     539        early_putchar_backspace:
     540       
     541                cmp $0x08, %al
     542                jne early_putchar_print
     543               
     544                /* Interpret backspace */
     545               
     546                cmp $0x0000, %bx
     547                je early_putchar_skip
     548               
     549                dec %bx
     550                jmp early_putchar_skip
    498551       
    499552        early_putchar_print:
     
    505558                inc %bx
    506559       
    507         early_putchar_newline:
     560        early_putchar_skip:
    508561       
    509562        /* Sanity check for the cursor on the last line */
     
    514567                movl $(PA2KA(0xb80a0)), %esi
    515568                movl $(PA2KA(0xb8000)), %edi
    516                 movl $1920, %ecx
    517                 rep movsw
     569                movl $960, %ecx
     570                rep movsl
    518571               
    519572                /* Clear the 24th row */
    520573                xorl %eax, %eax
    521                 movl $80, %ecx
    522                 rep stosw
     574                movl $40, %ecx
     575                rep stosl
    523576               
    524577                /* Go to row 24 */
     
    555608        ret
    556609
    557 .data
    558 .global interrupt_handler_size
    559 
    560 interrupt_handler_size: .long (h_end - h_start) / IDT_ITEMS
Note: See TracChangeset for help on using the changeset viewer.