github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/multiboot/internal/trampoline/trampoline_linux_amd64.s (about)

     1  // Copyright 2018 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // We want all the trampoline's assembly code to be located
     6  // in a contiguous byte range in a compiled binary.
     7  // Go compiler does not guarantee that. Still, current version
     8  // of compiler puts all pieces together.
     9  
    10  #include "textflag.h"
    11  
    12  #define MSR_EFER	0xC0000080
    13  #define EFER_LME	0xFFFFFEFF
    14  #define CR0_PG		0x0FFFFFFF
    15  
    16  #define DATA_SEGMENT	0x00CF92000000FFFF
    17  #define CODE_SEGMENT	0x00CF9A000000FFFF
    18  
    19  // func addrOfStart() uintptr
    20  TEXT ·addrOfStart(SB), $0-8
    21  	MOVQ	$start(SB), AX
    22  	MOVQ	AX, ret+0(FP)
    23  	RET
    24  
    25  // func addrOfEnd() uintptr
    26  TEXT ·addrOfEnd(SB), $0-8
    27  	MOVQ	$end(SB), AX
    28  	MOVQ	AX, ret+0(FP)
    29  	RET
    30  
    31  // func addrOfInfo() uintptr
    32  TEXT ·addrOfInfo(SB), $0-8
    33  	MOVQ	$info(SB), AX
    34  	MOVQ	AX, ret+0(FP)
    35  	RET
    36  
    37  // func addrOfMagic() uintptr
    38  TEXT ·addrOfMagic(SB), $0-8
    39  	MOVQ	$magic(SB), AX
    40  	MOVQ	AX, ret+0(FP)
    41  	RET
    42  
    43  // func addrOfEntry() uintptr
    44  TEXT ·addrOfEntry(SB), $0-8
    45  	MOVQ	$entry(SB), AX
    46  	MOVQ	AX, ret+0(FP)
    47  	RET
    48  
    49  TEXT start(SB),NOSPLIT,$0
    50  	// Create GDT pointer on stack.
    51  	LEAQ	gdt(SB), CX
    52  	SHLQ	$16, CX
    53  	ORQ	$(4*8 - 1), CX
    54  	PUSHQ	CX
    55  
    56  	LGDT	(SP)
    57  
    58  	// Store value of multiboot info addr in BX.
    59  	// Don't modify BX.
    60  	MOVL	info(SB), BX
    61  
    62  	// Store value of mu(l)tiboot magic in SI.
    63  	// Don't modify SI.
    64  	MOVL	magic(SB), SI
    65  
    66  	// Far return doesn't work on QEMU in 64-bit mode,
    67  	// let's do far jump.
    68  	//
    69  	// In a regular plan9 assembly we can do something like:
    70  	//	BYTE	$0xFF; BYTE $0x2D
    71  	//	LONG	$bootaddr(SB)
    72  	// TEXT bootaddr(SB),NOSPLIT,$0
    73  	//	LONG	$boot(SB)
    74  	//	LONG	$0x8
    75  	//
    76  	// Go compiler doesn't let us do it.
    77  	//
    78  	// Setup offset to make a far jump from boot(SB)
    79  	// to a final kernel in a 32-bit mode.
    80  	MOVL	entry(SB), AX
    81  	MOVL	AX, farjump32+1(SB)
    82  
    83  	// Setup offset to make a far jump to boot(SB)
    84  	// to switch from 64-bit mode to 32-bit mode.
    85  	LEAQ	boot(SB), CX
    86  	MOVL	CX, farjump64+6(SB)
    87  	JMP	farjump64(SB)
    88  
    89  
    90  TEXT boot(SB),NOSPLIT,$0
    91  	// We are in 32-bit mode now.
    92  	//
    93  	// Be careful editing this code!!! Go compiler
    94  	// interprets all commands as 64-bit commands.
    95  
    96  	// Disable paging.
    97  	MOVL	CR0, AX
    98  	ANDL	$CR0_PG, AX
    99  	MOVL	AX, CR0
   100  
   101  	// Disable long mode.
   102  	MOVL	$MSR_EFER, CX
   103  	RDMSR
   104  	ANDL	$EFER_LME, AX
   105  	WRMSR
   106  
   107  	// Disable PAE.
   108  	XORL	AX, AX
   109  	MOVL	AX, CR4
   110  
   111  	// Load data segments.
   112  	MOVL	$0x10, AX // GDT 0x10 data segment
   113  	BYTE	$0x8e; BYTE $0xd8 // MOVL AX, DS
   114  	BYTE	$0x8e; BYTE $0xc0 // MOVL AX, ES
   115  	BYTE	$0x8e; BYTE $0xd0 // MOVL AX, SS
   116  	BYTE	$0x8e; BYTE $0xe0 // MOVL AX, FS
   117  	BYTE	$0x8e; BYTE $0xe8 // MOVL AX, GS
   118  
   119  	// We stored the magic in SI before the far jump.
   120  	MOVL	SI, AX
   121  	JMP	farjump32(SB)
   122  
   123  TEXT farjump64(SB),NOSPLIT,$0
   124  	BYTE	$0xFF; BYTE $0x2D; LONG $0x0 // ljmp *(ip)
   125  
   126  	LONG	$0x0 // farjump64+6(SB)
   127  	LONG	$0x8 // code segment
   128  
   129  TEXT farjump32(SB),NOSPLIT,$0
   130  	// ljmp $0x18, offset
   131  	BYTE	$0xEA
   132  	LONG	$0x0 // farjump32+1(SB)
   133  	WORD	$0x18 // code segment
   134  
   135  TEXT gdt(SB),NOSPLIT,$0
   136  	QUAD	$0x0		// 0x0 null entry
   137  	QUAD	$CODE_SEGMENT	// 0x8
   138  	QUAD	$DATA_SEGMENT	// 0x10
   139  	QUAD	$CODE_SEGMENT	// 0x18
   140  
   141  TEXT info(SB),NOSPLIT,$0
   142  	LONG	$0x0
   143  
   144  TEXT entry(SB),NOSPLIT,$0
   145  	LONG	$0x0
   146  
   147  TEXT magic(SB),NOSPLIT,$0
   148  	LONG	$0x0
   149  
   150  TEXT end(SB),NOSPLIT,$0