Applied, thanks!

Damien Zammit, le mer. 21 janv. 2026 21:43:39 +0000, a ecrit:
> ---
>  x86_64/Makefrag.am |   1 +
>  x86_64/cpuboot.S   | 370 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 371 insertions(+)
>  create mode 100644 x86_64/cpuboot.S
> 
> diff --git a/x86_64/Makefrag.am b/x86_64/Makefrag.am
> index 73b402de..4cf1b1f2 100644
> --- a/x86_64/Makefrag.am
> +++ b/x86_64/Makefrag.am
> @@ -92,6 +92,7 @@ libkernel_a_SOURCES += \
>       i386/i386/percpu.h \
>       i386/i386/percpu.c \
>       x86_64/cswitch.S \
> +     x86_64/cpuboot.S \
>       x86_64/debug_trace.S \
>       x86_64/idt_inittab.S \
>       x86_64/locore.S \
> diff --git a/x86_64/cpuboot.S b/x86_64/cpuboot.S
> new file mode 100644
> index 00000000..b927c73c
> --- /dev/null
> +++ b/x86_64/cpuboot.S
> @@ -0,0 +1,370 @@
> +/*
> + *  Copyright (C) 2025 Free Software Foundation
> + *
> + * 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 the program ; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#if NCPUS > 1
> +#include <mach/machine/asm.h>
> +#include <i386/i386asm.h>
> +#include <i386/proc_reg.h>
> +#include <i386/apic.h>
> +#include <i386/cpu_number.h>
> +#include <i386/seg.h>
> +#include <i386/msr.h>
> +#include <i386/gdt.h>
> +
> +#define RELOC(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
> +
> +/* Number of 64 bit words */
> +#define GDT_DESCR_M64        2
> +#define GDT_TABLE_M64        14
> +
> +#define SEG_ACCESS_OFS       40
> +#define SEG_FLAGS_OFS        52
> +
> +.globl apboot, apbootend, gdt_descr_tmp, apboot_jmp_offset
> +
> +/* NOTE: apboot to apbootend is copied at runtime to a region above 64k
> + * so it can be called as a SIPI vector.  Manual relocations are thus 
> required
> + * on instructions that take absolute addresses.  Since we need to patch it,
> + * we use the data section to put this block of code.
> + */
> +
> +/* NB: cannot use (%rip) in below relocated code */
> +.section .boot.text
> +.align 4096
> +     .code16
> +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
> +
> +
> +     movl    %cr0, %eax
> +     andl    $~CR0_CLEAR_FLAGS, %eax
> +     orl     $CR0_SET_FLAGS, %eax
> +     movl    %eax, %cr0
> +
> +     lgdt    RELOC(gdt_descr_tmp)
> +     ljmpl   *RELOC(apboot_jmp_offset)
> +apboot32:
> +     .code32
> +     xorl    %eax, %eax
> +     movw    %ax, %ds
> +     movw    %ax, %es
> +     movw    %ax, %fs
> +     movw    %ax, %gs
> +     movw    $BOOT_DS, %ax
> +     movw    %ax, %ds
> +     movw    %ax, %es
> +     movw    %ax, %ss
> +
> +     /* Protected mode! */
> +
> +     /*
> +      * Prepare minimal page mapping to jump to 64 bit and to C code.
> +      * The first 4GB is identity mapped, and the first 2GB are re-mapped
> +      * to high addresses at KERNEL_MAP_BASE
> +      */
> +
> +     movl    $AP_p3table,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p4table)
> +     /*
> +      * Fill 4 entries in L3 table to cover the whole 32-bit 4GB address
> +      * space. Part of it might be remapped later if the kernel is mapped
> +      * below 4G.
> +      */
> +     movl    $AP_p2table,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3table)
> +     movl    $AP_p2table1,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3table + 8)
> +     movl    $AP_p2table2,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3table + 16)
> +     movl    $AP_p2table3,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3table + 24)
> +     /* point each page table level two entry to a page */
> +     mov     $0,%ecx
> +.map_p2_table:
> +     mov     $0x200000,%eax   // 2MiB page, should be always available
> +     mul     %ecx
> +     or      $(PTE_V|PTE_W|PTE_S),%eax  // enable 2MiB page instead of 4k
> +     mov     %eax,AP_p2table(,%ecx,8)
> +     inc     %ecx
> +     cmp     $2048,%ecx  // 512 entries per table, map 4 L2 tables
> +     jne     .map_p2_table
> +
> +     /*
> +      * KERNEL_MAP_BASE must me aligned to 2GB.
> +      * Depending on kernel starting address, we might need to add another
> +      * entry in the L4 table (controlling 512 GB chunks). In any case, we
> +      * add two entries in L3 table to make sure we map 2GB for the kernel.
> +      * Note that this may override part of the mapping create above.
> +      */
> +.kernel_map:
> +#if KERNEL_MAP_BASE >= (1U << 39)
> +     movl    $AP_p3ktable,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p4table + (8 * ((KERNEL_MAP_BASE >> 39) & 0x1FF)))  // 
> select 512G block
> +     movl    $AP_p2ktable1,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3ktable + (8 * ((KERNEL_MAP_BASE >> 30) & 0x1FF) ))  
> // select first 1G block
> +     movl    $AP_p2ktable2,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3ktable + (8 * (((KERNEL_MAP_BASE >> 30) & 0x1FF) + 
> 1) ))  // select second 1G block
> +#else
> +     movl    $AP_p2ktable1,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3table + (8 * ((KERNEL_MAP_BASE >> 30) & 0x1FF) ))  
> // select first 1G block
> +     movl    $AP_p2ktable2,%eax
> +     or      $(PTE_V|PTE_W),%eax
> +     movl    %eax,(AP_p3table + (8 * (((KERNEL_MAP_BASE >> 30) & 0x1FF) + 1) 
> ))  // select second 1G block
> +#endif
> +
> +     mov     $0,%ecx
> +.map_p2k_table:
> +     mov     $0x200000,%eax   // 2MiB page, should be always available
> +     mul     %ecx
> +     or      $(PTE_V|PTE_W|PTE_S),%eax  // enable 2MiB page instead of 4K
> +     mov     %eax,AP_p2ktable1(,%ecx,8)
> +     inc     %ecx
> +     cmp     $1024,%ecx  // 512 entries per table, map 2 L2 tables
> +     jne     .map_p2k_table
> +
> +switch64:
> +     /*
> +      * Jump to 64 bit mode, we have to
> +      * - enable PAE
> +      * - enable long mode
> +      * - enable paging and load the tables filled above in CR3
> +      * - jump to a 64-bit code segment at a 32-bit address
> +      */
> +     mov     %cr4,%eax
> +     or      $CR4_PAE,%eax
> +     mov     %eax,%cr4
> +     mov     $MSR_REG_EFER,%ecx
> +     rdmsr
> +     or      $MSR_REG_EFER_LONG_MODE_EN,%eax
> +     wrmsr
> +     mov     $AP_p4table,%eax
> +     mov     %eax,%cr3
> +     mov     %cr0,%eax
> +     or      $CR0_PG,%eax
> +     or      $CR0_WP,%eax
> +     mov     %eax,%cr0
> +
> +     /* Load null Interrupt descriptor table */
> +     movl    $apboot_idt_ptr, %eax
> +     lidtl   (%eax)
> +
> +     lgdtl   apboot_gdt64_descr
> +     ljmpl   $KERNEL_CS, $1f
> +1:
> +     .code64
> +     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
> +
> +     /* Long mode! */
> +
> +     /* Get CPU number into rbp */
> +     movq    $1, %rax
> +     cpuid
> +     shrl    $24, %ebx
> +     andb    %cs:apic_id_mask, %bl
> +     movq    $cpu_id_lut, %rdi
> +     movl    %cs:(%rdi, %rbx, 4), %ebp
> +
> +     /* set up mini stack to do far return */
> +     movq    $EXT(int_stack_top), %rdi
> +     movq    (%rdi, %rbp, 8), %rsp
> +
> +     /* jump to a 64-bit code segment at a 64-bit address */
> +     pushq   $KERNEL_CS
> +     pushq   $(start64 + KERNELBASE)
> +     retfq
> +
> +start64:
> +     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, %ss
> +
> +     /* Get CPU number into rbp */
> +     movl    $1, %eax
> +     cpuid
> +     shrl    $24, %ebx
> +     andb    %cs:apic_id_mask, %bl
> +     movq    $cpu_id_lut, %rdi
> +     movl    %cs:(%rdi, %rbx, 4), %ebp
> +
> +     /* Access per_cpu area */
> +     movq    %rbp, %rax
> +     movq    $PC_SIZE,%rbx
> +     mul     %rbx
> +     addq    $percpu_array, %rax
> +
> +     /* Record our cpu number */
> +     movl    %ebp, (PERCPU_CPU_ID)(%rax)
> +
> +     /* Set up GS base */
> +     movq    %rax, %rdx
> +     shrq    $32, %rdx
> +     movl    $MSR_REG_GSBASE, %ecx
> +     wrmsr
> +
> +     /* Set up Kernel GS base to 0 */
> +     xorl    %eax, %eax
> +     xorl    %edx, %edx
> +     movl    $MSR_REG_KGSBASE, %ecx
> +     wrmsr
> +
> +     /* 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(%edx)
> +     movq    $EXT(int_stack_top), %rdi
> +     movq    (%rdi, %rdx, 8), %rsp
> +
> +     /* Ensure stack alignment */
> +     andq    $(~0xf), %rsp
> +
> +     /* Reset EFLAGS to a known state */
> +     pushq   $0
> +     popfq
> +
> +     /* Finish the cpu configuration */
> +     call    EXT(cpu_ap_main) - KERNELBASE
> +
> +3:
> +     /* NOT REACHED */
> +     hlt
> +     jmp     3b
> +
> +.align 16
> +    .word 0
> +gdt_descr_tmp:
> +    .short 3*8-1
> +    .long RELOC(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
> +
> +.align 16
> +apboot_jmp_offset:
> +     .long RELOC(apboot32)
> +     .word BOOT_CS
> +
> +apbootend:
> +
> +.section .boot.data,"ax",@progbits
> +
> +.align 4096
> +AP_p4table:  .space 4096
> +AP_p3table:  .space 4096
> +AP_p2table:  .space 4096
> +AP_p2table1: .space 4096
> +AP_p2table2: .space 4096
> +AP_p2table3: .space 4096
> +AP_p3ktable: .space 4096
> +AP_p2ktable1:        .space 4096
> +AP_p2ktable2:        .space 4096
> +
> +.align 16
> +/* Make this long enough to hold 32b null IDT, but
> + * also long enough to inherit 64b null IDT
> + * so we don't have to reload it */
> +apboot_idt_ptr:
> +     .quad   0
> +     .word   0
> +
> +.code64
> +.align 16
> +apboot_gdt64_top:
> +     /* 6 bytes of padding */
> +     .long   0
> +     .word   0
> +apboot_gdt64_descr:
> +     .word   (GDT_TABLE_M64 * 8) - 1
> +apboot_gdt64_descr_addr:
> +     .quad   apboot_gdt64
> +apboot_gdt64:
> +     /* NULL segment */
> +     .quad   0
> +
> +     /* KERNEL_CS */
> +     .quad   ((ACC_P | ACC_CODE_R) << SEG_ACCESS_OFS) | (SZ_64 << 
> SEG_FLAGS_OFS)
> +
> +     /* KERNEL_DS */
> +     .quad   ((ACC_P | ACC_DATA_W) << SEG_ACCESS_OFS) | (SZ_64 << 
> SEG_FLAGS_OFS)
> +#endif
> -- 
> 2.51.0
> 
> 
> 

-- 
Samuel
RK > Some "PC speakers" are actually buzzers in some cases rather than
RK > real loudspeakers which give a squark rather than a beep.
DW They're not _that_ bad. Even on most recent hardware, mp3s played
DW through the PC speaker are relatively recognisable :)
 -+- lkml -+- 

Reply via email to