soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / device / oprom / realmode / x86_asm.S
bloba2c4aa56b93b0eeeb6cae26b896475fb96f0382f
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #define REALMODE_BASE           0x600
4 #define RELOCATED(x)    (x - __realmode_code + REALMODE_BASE)
6 #include <arch/ram_segs.h>
8 /* CR0 bits */
9 #define PE              (1 << 0)
11 /* This is the intXX interrupt handler stub code. It gets copied
12  * to the IDT and to some fixed addresses in the F segment. Before
13  * the code can used, it gets patched up by the C function copying
14  * it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#.
15  */
17         .code16
18         .globl __idt_handler
19 __idt_handler:
20         pushal
21         movb    $0, %al /* This instruction gets modified */
22         ljmp    $0, $__interrupt_handler_16bit
23         .globl __idt_handler_size
24 __idt_handler_size:
25         .long  . - __idt_handler
28 /* In order to be independent of coreboot's position in RAM
29  * we relocate a part of the code to the low megabyte, so the
30  * CPU can use it in real-mode. This code lives at __realmode_code.
31  */
32         .globl __realmode_code
33 __realmode_code:
35 /* Realmode function return. */
36 __realmode_ret = RELOCATED(.)
37         .long 0
39 /* Realmode IDT pointer structure. */
40 __realmode_idt = RELOCATED(.)
41         .word 1023      /* 16 bit limit */
42         .long 0         /* 24 bit base */
43         .word 0
45 /* Preserve old stack */
46 __stack = RELOCATED(.)
47         .long 0
49 /* Register store for realmode_call and realmode_interrupt */
50 __registers = RELOCATED(.)
51         .long 0 /*  0 - EAX */
52         .long 0 /*  4 - EBX */
53         .long 0 /*  8 - ECX */
54         .long 0 /* 12 - EDX */
55         .long 0 /* 16 - ESI */
56         .long 0 /* 20 - EDI */
58 /* 256 byte buffer, used by int10 */
59         .globl __realmode_buffer
60 __realmode_buffer:
61         .skip 256
63         .code32
64         .globl __realmode_call
65 __realmode_call:
66         /* save all registers to the stack */
67         pusha
68         pushf
70         /* Move the protected mode stack pointer to a safe place */
71         movl    %esp, __stack
72         movl    %esp, %ebp
74         /* This function is called with regparm=0 and we have to
75          * skip the 36 byte from pushf+pusha. Hence start at 40.
76          */
78         /* entry point */
79         movl    40(%ebp), %eax
80         mov     %ax, __lcall_instr + 1
81         andl    $0xffff0000, %eax
82         shrl    $4, %eax
83         mov     %ax, __lcall_instr + 3
85         /* initial register values */
86         movl    44(%ebp), %eax
87         movl    %eax, __registers +  0 /* eax */
88         movl    48(%ebp), %eax
89         movl    %eax, __registers +  4 /* ebx */
90         movl    52(%ebp), %eax
91         movl    %eax, __registers +  8 /* ecx */
92         movl    56(%ebp), %eax
93         movl    %eax, __registers + 12 /* edx */
94         movl    60(%ebp), %eax
95         movl    %eax, __registers + 16 /* esi */
96         movl    64(%ebp), %eax
97         movl    %eax, __registers + 20 /* edi */
99         /* Activate the right segment descriptor real mode. */
100         ljmp    $RAM_CODE16_SEG, $RELOCATED(1f)
102 .code16
103         /* 16 bit code from here on... */
105         /* Load the segment registers w/ properly configured
106          * segment descriptors. They will retain these
107          * configurations (limits, writability, etc.) once
108          * protected mode is turned off.
109          */
110         mov     $RAM_DATA16_SEG, %ax
111         mov     %ax, %ds
112         mov     %ax, %es
113         mov     %ax, %fs
114         mov     %ax, %gs
115         mov     %ax, %ss
117         /* Turn off protection */
118         movl    %cr0, %eax
119         andl    $~PE, %eax
120         movl    %eax, %cr0
122         /* Now really going into real mode */
123         ljmp    $0, $RELOCATED(1f)
125         /* Setup a stack: Put the stack at the end of page zero.
126          * That way we can easily share it between real and
127          * protected, since the 16 bit ESP at segment 0 will
128          * work for any case. */
129         mov     $0x0, %ax
130         mov     %ax, %ss
131         movl    $0x1000, %eax
132         movl    %eax, %esp
134         /* Load 16 bit IDT */
135         xor     %ax, %ax
136         mov     %ax, %ds
137         lidt    __realmode_idt
139         /* initialize registers for option ROM lcall */
140         movl    __registers +  0, %eax
141         movl    __registers +  4, %ebx
142         movl    __registers +  8, %ecx
143         movl    __registers + 12, %edx
144         movl    __registers + 16, %esi
145         movl    __registers + 20, %edi
147         /* Set all segments to 0x0000, ds to 0x0040 */
148         push    %ax
149         xor     %ax, %ax
150         mov     %ax, %es
151         mov     %ax, %fs
152         mov     %ax, %gs
153         mov     $0x40, %ax
154         mov     %ax, %ds
155         pop     %ax
157         /* ************************************ */
158 __lcall_instr = RELOCATED(.)
159         .byte 0x9a
160         .word 0x0000, 0x0000
161         /* ************************************ */
163         /*
164          * Here is end of real mode call and time to go back to protected mode.
165          * Before that its better to store current eax into some memory address
166          * so that context persist in protected mode too.
167         */
168         mov     %eax, __realmode_ret
170         /* If we got here, we are just about done.
171          * Need to get back to protected mode.
172          */
173         movl    %cr0, %eax
174         orl     $PE, %eax
175         movl    %eax, %cr0
177         /* Now that we are in protected mode
178          * jump to a 32 bit code segment.
179          */
180         ljmpl   $RAM_CODE_SEG, $RELOCATED(1f)
182         .code32
183         mov     $RAM_DATA_SEG, %ax
184         mov     %ax, %ds
185         mov     %ax, %es
186         mov     %ax, %fs
187         mov     %ax, %gs
188         mov     %ax, %ss
190         /* restore proper idt */
191         lidt    idtarg
193         /* restore stack pointer, eflags and register values */
194         movl    __stack, %esp
195         popf
196         popa
198         /* and exit */
199         /* return AX from OPROM call */
200         mov     __realmode_ret, %eax
201         ret
203         .globl __realmode_interrupt
204 __realmode_interrupt:
205         /* save all registers to the stack */
206         pusha
207         pushf
209         /* save the stack pointer */
210         movl    %esp, __stack
211         movl    %esp, %ebp
213         /* This function is called with regparm=0 and we have to
214          * skip the 36 byte from pushf+pusha. Hence start at 40.
215          */
217         /* prepare interrupt calling code */
218         movl    40(%ebp), %eax
219         movb    %al, __intXX_instr + 1 /* intno */
221         /* initial register values */
222         movl    44(%ebp), %eax
223         movl    %eax, __registers +  0 /* eax */
224         movl    48(%ebp), %eax
225         movl    %eax, __registers +  4 /* ebx */
226         movl    52(%ebp), %eax
227         movl    %eax, __registers +  8 /* ecx */
228         movl    56(%ebp), %eax
229         movl    %eax, __registers + 12 /* edx */
230         movl    60(%ebp), %eax
231         movl    %eax, __registers + 16 /* esi */
232         movl    64(%ebp), %eax
233         movl    %eax, __registers + 20 /* edi */
235         /*  This configures CS properly for real mode. */
236         ljmp    $RAM_CODE16_SEG, $RELOCATED(1f)
238         .code16 /* 16 bit code from here on... */
240         /* Load the segment registers w/ properly configured segment
241          * descriptors.  They will retain these configurations (limits,
242          * writability, etc.) once protected mode is turned off.
243          */
244         mov     $RAM_DATA16_SEG, %ax
245         mov     %ax, %ds
246         mov     %ax, %es
247         mov     %ax, %fs
248         mov     %ax, %gs
249         mov     %ax, %ss
251         /* Turn off protected mode */
252         movl    %cr0, %eax
253         andl    $~PE, %eax
254         movl    %eax, %cr0
256         /* Now really going into real mode */
257         ljmpl   $0, $RELOCATED(1f)
260         /* put the stack at the end of page zero.  That way we can easily
261          * share it between real mode and protected mode, because %esp and
262          * %ss:%sp point to the same memory.
263          */
264         /* setup a stack */
265         mov     $0x0, %ax
266         mov     %ax, %ss
267         movl    $0x1000, %eax
268         movl    %eax, %esp
270         /* Load 16-bit intXX IDT */
271         xor     %ax, %ax
272         mov     %ax, %ds
273         lidt    __realmode_idt
275         /* initialize registers for intXX call */
276         movl    __registers +  0, %eax
277         movl    __registers +  4, %ebx
278         movl    __registers +  8, %ecx
279         movl    __registers + 12, %edx
280         movl    __registers + 16, %esi
281         movl    __registers + 20, %edi
283         /* Set all segments to 0x0000 */
284         push    %ax
285         xor     %ax, %ax
286         mov     %ax, %ds
287         mov     %ax, %es
288         mov     %ax, %fs
289         mov     %ax, %gs
290         pop     %ax
292 __intXX_instr = RELOCATED(.)
293         .byte 0xcd, 0x00 /* This becomes intXX */
295         /*
296          * Here is end of real mode call and time to go back to protected mode.
297          * Before that its better to store current eax into some memory address
298          * so that context persist in protected mode too.
299         */
300         mov     %eax, __realmode_ret
302         /* Ok, the job is done, now go back to protected mode coreboot */
303         movl    %cr0, %eax
304         orl     $PE, %eax
305         movl    %eax, %cr0
307         /* Now that we are in protected mode jump to a 32-bit code segment. */
308         ljmpl   $RAM_CODE_SEG, $RELOCATED(1f)
310         .code32
311         mov     $RAM_DATA_SEG, %ax
312         mov     %ax, %ds
313         mov     %ax, %es
314         mov     %ax, %fs
315         mov     %ax, %gs
316         mov     %ax, %ss
318         /* restore coreboot's 32-bit IDT */
319         lidt    idtarg
321         /* restore stack pointer, eflags and register values and exit */
322         movl    __stack, %esp
323         popf
324         popa
325         /* return AX from OPROM call */
326         mov     __realmode_ret, %eax
327         ret
329 /* This is the 16-bit interrupt entry point called by the IDT stub code.
331  * Before this code is called, %eax is pushed to the stack, and the
332  * interrupt number is loaded into %al. On return this function cleans up
333  * for its caller.
334  */
335         .code16
336 __interrupt_handler_16bit = RELOCATED(.)
337         push    %ds
338         push    %es
339         push    %fs
340         push    %gs
342         /* Clear DF to not break ABI assumptions */
343         cld
345         /* Clean up the interrupt number. We could have done this in the stub,
346          * but it would have cost 2 more bytes per stub entry.
347          */
348         andl    $0xff, %eax
349         pushl   %eax            /* ... and make it the first parameter */
351         /* Switch to protected mode */
352         movl    %cr0, %eax
353         orl     $PE, %eax
354         movl    %eax, %cr0
356         /* ... and jump to a 32 bit code segment. */
357         ljmpl   $RAM_CODE_SEG, $RELOCATED(1f)
359         .code32
360         mov     $RAM_DATA_SEG, %ax
361         mov     %ax, %ds
362         mov     %ax, %es
363         mov     %ax, %fs
364         mov     %ax, %gs
365         mov     %ax, %ss
367         lidt    idtarg
369         /* Call the C interrupt handler */
370         movl    $interrupt_handler, %eax
371         call    *%eax
373         /* Now return to real mode ... */
374         ljmp    $RAM_CODE16_SEG, $RELOCATED(1f)
376         .code16
377         /* Load the segment registers with properly configured segment
378          * descriptors.  They will retain these configurations (limits,
379          * writability, etc.) once protected mode is turned off.
380          */
381         mov     $RAM_DATA16_SEG, %ax
382         mov     %ax, %ds
383         mov     %ax, %es
384         mov     %ax, %fs
385         mov     %ax, %gs
386         mov     %ax, %ss
388         /* Disable Protected Mode */
389         movl    %cr0, %eax
390         andl    $~PE, %eax
391         movl    %eax, %cr0
393         /* Now really going into real mode */
394         ljmp $0,  $RELOCATED(1f)
396         /* Restore real-mode stack segment */
397         mov     $0x0, %ax
398         mov     %ax, %ss
400         /* Restore 16 bit IDT */
401         xor     %ax, %ax
402         mov     %ax, %ds
403         lidt    __realmode_idt
405         /* Restore all registers, including those
406          * manipulated by the C handler
407          */
408         popl    %eax
409         pop     %gs
410         pop     %fs
411         pop     %es
412         pop     %ds
413         popal
414         iret
416         .globl __realmode_code_size
417 __realmode_code_size:
418         .long  . - __realmode_code
420         .code32