1/*
2 * Copyright (c) 2010-2015 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6/**
7 * @file
8 * @brief Crt0 module for the IA-32 boards
9 *
10 * This module contains the initial code executed by the Zephyr Kernel ELF image
11 * after having been loaded into RAM.
12 *
13 * Note that most addresses (functions and variables) must be in physical
14 * address space. Depending on page table setup, they may or may not be
15 * available in virtual address space after loading of page table.
16 */
17
18#include <zephyr/arch/x86/ia32/asm.h>
19#include <zephyr/arch/x86/msr.h>
20#include <kernel_arch_data.h>
21#include <zephyr/arch/cpu.h>
22#include <zephyr/arch/x86/multiboot.h>
23#include <x86_mmu.h>
24#include <zephyr/kernel/mm.h>
25
26	/* exports (private APIs) */
27
28	GTEXT(__start)
29
30	/* externs */
31	GTEXT(z_prep_c)
32	GTEXT(z_bss_zero)
33	GTEXT(z_data_copy)
34
35	GDATA(_idt_base_address)
36	GDATA(z_interrupt_stacks)
37	GDATA(z_x86_idt)
38#ifndef CONFIG_GDT_DYNAMIC
39	GDATA(_gdt)
40#endif
41
42
43#if defined(CONFIG_X86_SSE)
44	GDATA(_sse_mxcsr_default_value)
45#endif
46
47#if defined(CONFIG_THREAD_LOCAL_STORAGE)
48	GTEXT(z_x86_early_tls_update_gdt)
49#endif
50
51	GDATA(x86_cpu_boot_arg)
52
53.macro install_page_tables
54#ifdef CONFIG_X86_MMU
55	/* Enable paging. If virtual memory is enabled, the instruction pointer
56	 * is currently at a physical address. There is an identity mapping
57	 * for all RAM, plus a virtual mapping of RAM starting at
58	 * CONFIG_KERNEL_VM_BASE using the same paging structures.
59	 *
60	 * Until we enable these page tables, only physical memory addresses
61	 * work.
62	 */
63	movl	$Z_MEM_PHYS_ADDR(z_x86_kernel_ptables), %eax
64	movl	%eax, %cr3
65
66#ifdef CONFIG_X86_PAE
67	/* Enable PAE */
68	movl	%cr4, %eax
69	orl	$CR4_PAE, %eax
70	movl	%eax, %cr4
71
72	/* IA32_EFER NXE bit set */
73	movl	$0xC0000080, %ecx
74	rdmsr
75	orl	$0x800, %eax
76	wrmsr
77#else
78	/* Enable Page Size Extensions (allowing 4MB pages).
79	 * This is ignored if PAE is enabled so no need to do
80	 * this above in PAE code.
81	 */
82	movl	%cr4, %eax
83	orl	$CR4_PSE, %eax
84	movl	%eax, %cr4
85#endif /* CONFIG_X86_PAE */
86
87	/* Enable paging (CR0.PG, bit 31) / write protect (CR0.WP, bit 16) */
88	movl	%cr0, %eax
89	orl	$(CR0_PG | CR0_WP), %eax
90	movl	%eax, %cr0
91
92#ifdef Z_VM_KERNEL
93	/* Jump to a virtual address, which works because the identity and
94	 * virtual mappings both are to the same physical address.
95	 */
96	ljmp    $CODE_SEG, $vm_enter
97vm_enter:
98	/* We are now executing in virtual memory. We'll un-map the identity
99	 * mappings later once we are in the C domain
100	 */
101#endif /* Z_VM_KERNEL */
102
103#endif /* CONFIG_X86_MMU */
104.endm
105
106SECTION_FUNC(BOOT_TEXT, __start)
107
108#include "../common.S"
109
110	/* Enable write-back caching by clearing the NW and CD bits */
111	movl	%cr0, %eax
112	andl	$0x9fffffff, %eax
113	movl	%eax, %cr0
114
115	/*
116	 * Ensure interrupts are disabled.  Interrupts are enabled when
117	 * the first context switch occurs.
118	 */
119
120	cli
121
122	/*
123	 * Although the bootloader sets up an Interrupt Descriptor Table (IDT)
124	 * and a Global Descriptor Table (GDT), the specification encourages
125	 * booted operating systems to setup their own IDT and GDT.
126	 */
127#if CONFIG_SET_GDT
128	/* load 32-bit operand size GDT */
129	lgdt	Z_MEM_PHYS_ADDR(_gdt_rom)
130
131	/* If we set our own GDT, update the segment registers as well.
132	 */
133	movw	$DATA_SEG, %ax	/* data segment selector (entry = 3) */
134	movw	%ax, %ds	/* set DS */
135	movw	%ax, %es	/* set ES */
136	movw	%ax, %ss	/* set SS */
137	xorw	%ax, %ax	/* AX = 0 */
138	movw	%ax, %fs	/* Zero FS */
139	movw	%ax, %gs	/* Zero GS */
140
141	ljmp	$CODE_SEG, $Z_MEM_PHYS_ADDR(__csSet)	/* set CS = 0x08 */
142
143__csSet:
144#endif /* CONFIG_SET_GDT */
145
146#if !defined(CONFIG_FPU)
147	/*
148	 * Force an #NM exception for floating point instructions
149	 * since FP support hasn't been configured
150	 */
151
152	movl	%cr0, %eax		/* move CR0 to EAX */
153	orl	$0x2e, %eax		/* CR0[NE+TS+EM+MP]=1 */
154	movl	%eax, %cr0		/* move EAX to CR0 */
155#else
156	/*
157	 * Permit use of x87 FPU instructions
158	 *
159	 * Note that all floating point exceptions are masked by default,
160	 * and that _no_ handler for x87 FPU exceptions (#MF) is provided.
161	 */
162
163	movl	%cr0, %eax		/* move CR0 to EAX */
164	orl	$0x22, %eax		/* CR0[NE+MP]=1 */
165	andl	$~0xc, %eax		/* CR0[TS+EM]=0 */
166	movl	%eax, %cr0		/* move EAX to CR0 */
167
168	fninit				/* set x87 FPU to its default state */
169
170  #if defined(CONFIG_X86_SSE)
171	/*
172	 * Permit use of SSE instructions
173	 *
174	 * Note that all SSE exceptions are masked by default,
175	 * and that _no_ handler for SSE exceptions (#XM) is provided.
176	 */
177
178	movl	%cr4, %eax		/* move CR4 to EAX */
179	orl	$0x200, %eax		/* CR4[OSFXSR] = 1 */
180	andl	$~0x400, %eax		/* CR4[OSXMMEXCPT] = 0 */
181	movl	%eax, %cr4		/* move EAX to CR4 */
182
183	ldmxcsr Z_MEM_PHYS_ADDR(_sse_mxcsr_default_value)   /* initialize SSE control/status reg */
184
185  #endif /* CONFIG_X86_SSE */
186
187#endif /* !CONFIG_FPU */
188
189	/*
190	 * Set the stack pointer to the area used for the interrupt stack.
191	 * Note this stack is used during the execution of __start() and
192	 * z_cstart() until the multi-tasking kernel is initialized.  The
193	 * dual-purposing of this area of memory is safe since
194	 * interrupts are disabled until the first context switch.
195	 *
196	 * kernel/init.c enforces that the z_interrupt_stacks pointer and
197	 * the ISR stack size are some multiple of ARCH_STACK_PTR_ALIGN, which
198	 * is at least 4.
199	 */
200#ifdef CONFIG_INIT_STACKS
201	movl $0xAAAAAAAA, %eax
202	leal Z_MEM_PHYS_ADDR(z_interrupt_stacks), %edi
203#ifdef CONFIG_X86_STACK_PROTECTION
204	addl $4096, %edi
205#endif
206	stack_size_dwords = (CONFIG_ISR_STACK_SIZE / 4)
207	movl $stack_size_dwords, %ecx
208	rep  stosl
209#endif
210
211	movl	$Z_MEM_PHYS_ADDR(z_interrupt_stacks), %esp
212#ifdef CONFIG_X86_STACK_PROTECTION
213	/* In this configuration, all stacks, including IRQ stack, are declared
214	 * with a 4K non-present guard page preceding the stack buffer
215	 */
216	addl	$(CONFIG_ISR_STACK_SIZE + 4096), %esp
217#else
218	addl	$CONFIG_ISR_STACK_SIZE, %esp
219#endif
220
221#ifdef CONFIG_XIP
222	/* Copy data from flash to RAM.
223	 *
224	 * This is a must is CONFIG_GDT_DYNAMIC is enabled,
225	 * as _gdt needs to be in RAM.
226	 */
227	call	z_data_copy
228#endif
229
230	/* Note that installing page tables must be done after
231	 * z_data_copy() as the page tables are being copied into
232	 * RAM there.
233	 */
234	install_page_tables
235
236#ifdef CONFIG_GDT_DYNAMIC
237	/* activate RAM-based Global Descriptor Table (GDT) */
238	lgdt	%ds:_gdt
239#endif
240
241#if defined(CONFIG_X86_ENABLE_TSS)
242	mov $MAIN_TSS, %ax
243	ltr %ax
244#endif
245
246#ifdef Z_VM_KERNEL
247	/* Need to reset the stack to virtual address after
248	 * page table is loaded.
249	 */
250
251	movl	$z_interrupt_stacks, %esp
252#ifdef CONFIG_X86_STACK_PROTECTION
253	addl	$(CONFIG_ISR_STACK_SIZE + 4096), %esp
254#else
255	addl	$CONFIG_ISR_STACK_SIZE, %esp
256#endif
257#endif /* Z_VM_KERNEL */
258
259#ifdef CONFIG_THREAD_LOCAL_STORAGE
260	pushl %esp
261	call z_x86_early_tls_update_gdt
262	popl %esp
263#endif
264	/* Clear BSS */
265#ifdef CONFIG_LINKER_USE_BOOT_SECTION
266	call	z_bss_zero_boot
267#endif
268#ifdef CONFIG_LINKER_USE_PINNED_SECTION
269	call	z_bss_zero_pinned
270#endif
271#ifdef CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT
272	/* Don't clear BSS if the section is not present
273	 * in memory at boot. Or else it would cause page
274	 * faults. Zeroing BSS will be done later once the
275	 * the paging mechanism has been initialized.
276	 */
277	call	z_bss_zero
278#endif
279
280	/* load 32-bit operand size IDT */
281	lidt	z_x86_idt
282
283	movl	$x86_cpu_boot_arg, %ebp
284	/* Boot type to multiboot, ebx content will help to mitigate */
285	movl	$MULTIBOOT_BOOT_TYPE, \
286			__x86_boot_arg_t_boot_type_OFFSET(%ebp)
287	/* pointer to multiboot info, or NULL */
288	movl	%ebx, __x86_boot_arg_t_arg_OFFSET(%ebp)
289	pushl	$x86_cpu_boot_arg
290	call	z_prep_c	/* enter kernel; never returns */
291
292#if defined(CONFIG_X86_SSE)
293
294	/* SSE control & status register initial value */
295
296_sse_mxcsr_default_value:
297	.long	0x1f80			/* all SSE exceptions clear & masked */
298
299#endif /* CONFIG_X86_SSE */
300
301	 /* Interrupt Descriptor Table (IDT) definition */
302
303z_x86_idt:
304	.word	(CONFIG_IDT_NUM_VECTORS * 8) - 1 /* limit: size of IDT-1 */
305
306	/*
307	 * Physical start address = 0.  When executing natively, this
308	 * will be placed at the same location as the interrupt vector table
309	 * setup by the BIOS (or GRUB?).
310	 */
311
312	/* IDT table start address */
313	.long	_idt_base_address
314
315
316#ifdef CONFIG_SET_GDT
317	/*
318	 * The following 3 GDT entries implement the so-called "basic
319	 * flat model", i.e. a single code segment descriptor and a single
320	 * data segment descriptor, giving the kernel access to a continuous,
321	 * unsegmented address space.  Both segment descriptors map the entire
322	 * linear address space (i.e. 0 to 4 GB-1), thus the segmentation
323	 * mechanism will never generate "out of limit memory reference"
324	 * exceptions even if physical memory does not reside at the referenced
325	 * address.
326	 *
327	 * The 'A' (accessed) bit in the type field is set for all the
328	 * data/code segment descriptors to accommodate placing these entries
329	 * in ROM, to prevent the processor from freaking out when it tries
330	 * and fails to set it.
331	 */
332
333SECTION_VAR(PINNED_RODATA, _gdt_rom)
334#ifndef CONFIG_GDT_DYNAMIC
335_gdt:
336#endif
337
338	/* GDT should be aligned on 8-byte boundary for best processor
339	 * performance, see Section 3.5.1 of IA architecture SW developer
340	 * manual, Vol 3.
341	 */
342
343	.balign 8
344
345	/* Entry 0 (selector=0x0000): The "NULL descriptor". The CPU never
346	 * actually looks at this entry, so we stuff 6-byte the pseudo
347	 * descriptor here */
348
349	/* Limit on GDT */
350	.word Z_MEM_PHYS_ADDR(_gdt_rom_end) - Z_MEM_PHYS_ADDR(_gdt_rom) - 1
351	/* table address: _gdt_rom */
352	.long Z_MEM_PHYS_ADDR(_gdt_rom)
353	.word   0x0000
354
355	/* Entry 1 (selector=0x0008): Code descriptor: DPL0 */
356
357	.word   0xffff		/* limit: xffff */
358	.word   0x0000		/* base : xxxx0000 */
359	.byte   0x00		/* base : xx00xxxx */
360	.byte   0x9b		/* Accessed, Code e/r, Present, DPL0 */
361	.byte   0xcf		/* limit: fxxxx, Page Gra, 32bit */
362	.byte   0x00		/* base : 00xxxxxx */
363
364	/* Entry 2 (selector=0x0010): Data descriptor: DPL0 */
365
366	.word   0xffff		/* limit: xffff */
367	.word   0x0000		/* base : xxxx0000 */
368	.byte   0x00		/* base : xx00xxxx */
369	.byte   0x93		/* Accessed, Data r/w, Present, DPL0 */
370	.byte   0xcf		/* limit: fxxxx, Page Gra, 32bit */
371	.byte   0x00		/* base : 00xxxxxx */
372
373_gdt_rom_end:
374#endif
375