Changeset 89c57b6 in mainline for kernel/arch/ia32/src/asm.S
- Timestamp:
- 2011-04-13T14:45:41Z (14 years ago)
- 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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/ia32/src/asm.S
rcefb126 r89c57b6 1 1 /* 2 * Copyright (c) 20 01Jakub Jermar2 * Copyright (c) 2010 Jakub Jermar 3 3 * All rights reserved. 4 4 * … … 31 31 */ 32 32 33 /**34 * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int35 * has no error word and 1 means interrupt with error word36 *37 */38 #define ERROR_WORD_INTERRUPT_LIST 0x00027d0039 40 33 #include <arch/pm.h> 34 #include <arch/cpu.h> 41 35 #include <arch/mm/page.h> 42 36 … … 44 38 .global paging_on 45 39 .global enable_l_apic_in_msr 46 .global interrupt_handlers47 .global memsetb48 .global memsetw49 .global memcpy50 40 .global memcpy_from_uspace 51 41 .global memcpy_from_uspace_failover_address … … 54 44 .global early_putchar 55 45 56 /* Wrapper for generic memsetb */57 memsetb:58 jmp _memsetb59 60 /* Wrapper for generic memsetw */61 memsetw:62 jmp _memsetw63 64 46 #define MEMCPY_DST 4 65 47 #define MEMCPY_SRC 8 … … 81 63 * 82 64 */ 83 memcpy:84 65 memcpy_from_uspace: 85 66 memcpy_to_uspace: … … 155 136 ret 156 137 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 214 145 #define ISTATE_OFFSET_EBP_FRAME 28 215 146 #define ISTATE_OFFSET_EIP_FRAME 32 … … 231 162 #define ISTATE_SOFT_SIZE 52 232 163 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 174 sysenter_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 254 int_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 341 int_\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 293 361 .else 294 362 /* 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 300 364 */ 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 406 366 .endif 407 367 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 412 451 .endm 413 452 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 418 458 interrupt_handlers: 419 h_start: 420 handler 0 IDT_ITEMS421 h_end: 459 .irp cnt, LIST_0_63 460 handler \cnt 461 .endr 422 462 423 463 /** Print Unicode character to EGA display. … … 428 468 * Since the EGA can only display Extended ASCII (usually 429 469 * ISO Latin 1) characters, some of the Unicode characters 430 * can be displayed in a wrong way. Only the newline character431 * isinterpreted, all other characters (even unprintable) are470 * can be displayed in a wrong way. Only newline and backspace 471 * are interpreted, all other characters (even unprintable) are 432 472 * printed verbatim. 433 473 * … … 481 521 482 522 cmp $0x0a, %al 483 jne early_putchar_ print523 jne early_putchar_backspace 484 524 485 525 /* Interpret newline */ … … 495 535 subw %dx, %bx 496 536 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 498 551 499 552 early_putchar_print: … … 505 558 inc %bx 506 559 507 early_putchar_ newline:560 early_putchar_skip: 508 561 509 562 /* Sanity check for the cursor on the last line */ … … 514 567 movl $(PA2KA(0xb80a0)), %esi 515 568 movl $(PA2KA(0xb8000)), %edi 516 movl $ 1920, %ecx517 rep movs w569 movl $960, %ecx 570 rep movsl 518 571 519 572 /* Clear the 24th row */ 520 573 xorl %eax, %eax 521 movl $ 80, %ecx522 rep stos w574 movl $40, %ecx 575 rep stosl 523 576 524 577 /* Go to row 24 */ … … 555 608 ret 556 609 557 .data558 .global interrupt_handler_size559 560 interrupt_handler_size: .long (h_end - h_start) / IDT_ITEMS
Note:
See TracChangeset
for help on using the changeset viewer.