/*
* Copyright (c) 2022 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#define M(addr) (addr - apboot)
#define CR0_CLEAR_FLAGS_CACHE_ENABLE (CR0_CD | CR0_NW)
#define CR0_SET_FLAGS (CR0_CLEAR_FLAGS_CACHE_ENABLE | CR0_PE)
#define CR0_CLEAR_FLAGS (CR0_PG | CR0_AM | CR0_WP | CR0_NE | CR0_TS | CR0_EM | CR0_MP)
#define BOOT_CS 0x8
#define BOOT_DS 0x10
.data
.align 16
apboot_idt_ptr:
.long 0
.align 16
.word 0
apboot_gdt_descr:
.word 14*8-1
.long apboot_gdt - KERNELBASE
.align 16
apboot_gdt:
/* NULL segment = 0x0 */
.quad 0
/* KERNEL_CS = 0x8 */
.word 0xffff /* Segment limit first 0-15 bits*/
.word (-KERNELBASE) & 0xffff /*Base first 0-15 bits*/
.byte ((-KERNELBASE) >> 16) & 0xff /*Base 16-23 bits */
.byte ACC_PL_K | ACC_CODE_R | ACC_P /*Access byte */
.byte ((SZ_32 | SZ_G) << 4) | 0xf /* High 4 bits */
.byte ((-KERNELBASE) >> 24) & 0xff /*Base 24-31 bits */
/* KERNEL_DS = 0x10 */
.word 0xffff /*Segment limit */
.word (-KERNELBASE) & 0xffff /*Base first 0-15 bits*/
.byte ((-KERNELBASE) >> 16) & 0xff
.byte ACC_PL_K | ACC_DATA_W | ACC_P /*Access byte*/
.byte ((SZ_32 | SZ_G) << 4) | 0xf /* High 4 bits */
.byte ((-KERNELBASE) >> 24) & 0xff /*Base 24-31 bits */
/* LDT = 0x18 */
.quad 0
/* TSS = 0x20 */
.quad 0
/* USER_LDT = 0x28 */
.quad 0
/* USER_TSS = 0x30 */
.quad 0
/* LINEAR = 0x38 */
.quad 0
/* FPREGS = 0x40 */
.quad 0
/* USER_GDT = 0x48 and 0x50 */
.quad 0
.quad 0
/* USER_TSS64 = 0x58 */
.quad 0
/* USER_TSS64 = 0x60 */
.quad 0
/* boot GS = 0x68 */
.word 0xffff
apboot_percpu_low:
.word 0
apboot_percpu_med:
.byte 0
.byte ACC_PL_K | ACC_DATA_W | ACC_P
.byte ((SZ_32 | SZ_G) << 4) | 0xf
apboot_percpu_high:
.byte 0
.globl apboot, apbootend, gdt_descr_tmp, apboot_jmp_offset
.align 16
.code16
apboot:
_apboot:
/* This is now address CS:0 in real mode */
/* Set data seg same as code seg */
mov %cs, %dx
mov %dx, %ds
cli
xorl %eax, %eax
movl %eax, %cr3
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
lgdt M(gdt_descr_tmp)
movl %cr0, %eax
andl $~CR0_CLEAR_FLAGS, %eax
orl $CR0_SET_FLAGS, %eax
movl %eax, %cr0
/* ljmpl with relocation from machine_init */
.byte 0x66
.byte 0xea
apboot_jmp_offset:
.long M(0f)
.word BOOT_CS
0:
.code32
/* Protected mode! */
movw $BOOT_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
lgdtl apboot_gdt_descr - KERNELBASE
ljmpl $KERNEL_CS, $1f
1:
xorl %eax, %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw $KERNEL_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* Get CPU number */
movl $1, %eax
cpuid
shrl $24, %ebx
movl %cs:CX(cpu_id_lut, %ebx), %ecx
/* Access per_cpu area */
movl %ecx,%eax
movl $PC_SIZE,%ebx
mul %ebx
addl $percpu_array - KERNELBASE, %eax
/* Record our cpu number */
movl %ecx, (PERCPU_CPU_ID + KERNELBASE)(%eax)
/* Set up temporary percpu descriptor */
movw %ax, apboot_percpu_low
shr $16, %eax
movb %al, apboot_percpu_med
shr $8, %ax
movb %al, apboot_percpu_high
movw $PERCPU_DS, %ax
movw %ax, %gs
/* Load null Interrupt descriptor table */
mov apboot_idt_ptr, %ebx
lidt (%ebx)
/* Enable local apic in xAPIC mode */
xorl %eax, %eax
xorl %edx, %edx
movl $APIC_MSR, %ecx
rdmsr
orl $APIC_MSR_ENABLE, %eax
andl $(~(APIC_MSR_BSP | APIC_MSR_X2APIC)), %eax
movl $APIC_MSR, %ecx
wrmsr
/* Load int_stack_top[cpu] -> esp */
CPU_NUMBER_NO_STACK(%edx)
movl CX(EXT(int_stack_top), %edx), %esp
/* Ensure stack alignment */
andl $0xfffffff0, %esp
/* Reset EFLAGS to a known state */
pushl $0
popfl
/* Finish the cpu configuration */
call EXT(cpu_ap_main)
/* NOT REACHED */
hlt
.align 16
.word 0
gdt_descr_tmp:
.short 3*8-1
.long M(gdt_tmp)
.align 16
gdt_tmp:
/* 0 */
.quad 0
/* BOOT_CS */
.word 0xffff
.word 0x0000
.byte 0x00
.byte ACC_PL_K | ACC_CODE_R | ACC_P
.byte ((SZ_32 | SZ_G) << 4) | 0xf
.byte 0x00
/* BOOT_DS */
.word 0xffff
.word 0x0000
.byte 0x00
.byte ACC_PL_K | ACC_DATA_W | ACC_P
.byte ((SZ_32 | SZ_G) << 4) | 0xf
.byte 0x00
_apbootend:
apbootend: