| .. | .. |
|---|
| 454 | 454 | /* Save the trampoline address in RCX */ |
|---|
| 455 | 455 | movq %rax, %rcx |
|---|
| 456 | 456 | |
|---|
| 457 | + /* Set up 32-bit addressable stack */ |
|---|
| 458 | + leaq TRAMPOLINE_32BIT_STACK_END(%rcx), %rsp |
|---|
| 459 | + |
|---|
| 457 | 460 | /* |
|---|
| 458 | | - * Load the address of trampoline_return() into RDI. |
|---|
| 459 | | - * It will be used by the trampoline to return to the main code. |
|---|
| 461 | + * Preserve live 64-bit registers on the stack: this is necessary |
|---|
| 462 | + * because the architecture does not guarantee that GPRs will retain |
|---|
| 463 | + * their full 64-bit values across a 32-bit mode switch. |
|---|
| 464 | + */ |
|---|
| 465 | + pushq %rbp |
|---|
| 466 | + pushq %rbx |
|---|
| 467 | + pushq %rsi |
|---|
| 468 | + |
|---|
| 469 | + /* |
|---|
| 470 | + * Push the 64-bit address of trampoline_return() onto the new stack. |
|---|
| 471 | + * It will be used by the trampoline to return to the main code. Due to |
|---|
| 472 | + * the 32-bit mode switch, it cannot be kept it in a register either. |
|---|
| 460 | 473 | */ |
|---|
| 461 | 474 | leaq trampoline_return(%rip), %rdi |
|---|
| 475 | + pushq %rdi |
|---|
| 462 | 476 | |
|---|
| 463 | 477 | /* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */ |
|---|
| 464 | 478 | pushq $__KERNEL32_CS |
|---|
| .. | .. |
|---|
| 466 | 480 | pushq %rax |
|---|
| 467 | 481 | lretq |
|---|
| 468 | 482 | trampoline_return: |
|---|
| 483 | + /* Restore live 64-bit registers */ |
|---|
| 484 | + popq %rsi |
|---|
| 485 | + popq %rbx |
|---|
| 486 | + popq %rbp |
|---|
| 487 | + |
|---|
| 469 | 488 | /* Restore the stack, the 32-bit trampoline uses its own stack */ |
|---|
| 470 | 489 | leaq rva(boot_stack_end)(%rbx), %rsp |
|---|
| 471 | 490 | |
|---|
| .. | .. |
|---|
| 586 | 605 | /* |
|---|
| 587 | 606 | * This is the 32-bit trampoline that will be copied over to low memory. |
|---|
| 588 | 607 | * |
|---|
| 589 | | - * RDI contains the return address (might be above 4G). |
|---|
| 608 | + * Return address is at the top of the stack (might be above 4G). |
|---|
| 590 | 609 | * ECX contains the base address of the trampoline memory. |
|---|
| 591 | 610 | * Non zero RDX means trampoline needs to enable 5-level paging. |
|---|
| 592 | 611 | */ |
|---|
| .. | .. |
|---|
| 595 | 614 | movl $__KERNEL_DS, %eax |
|---|
| 596 | 615 | movl %eax, %ds |
|---|
| 597 | 616 | movl %eax, %ss |
|---|
| 598 | | - |
|---|
| 599 | | - /* Set up new stack */ |
|---|
| 600 | | - leal TRAMPOLINE_32BIT_STACK_END(%ecx), %esp |
|---|
| 601 | 617 | |
|---|
| 602 | 618 | /* Disable paging */ |
|---|
| 603 | 619 | movl %cr0, %eax |
|---|
| .. | .. |
|---|
| 658 | 674 | .code64 |
|---|
| 659 | 675 | SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled) |
|---|
| 660 | 676 | /* Return from the trampoline */ |
|---|
| 661 | | - jmp *%rdi |
|---|
| 677 | + retq |
|---|
| 662 | 678 | SYM_FUNC_END(.Lpaging_enabled) |
|---|
| 663 | 679 | |
|---|
| 664 | 680 | /* |
|---|