3b184b71df
We have no known use for having the CPU track whether GDT descriptors have been accessed or not. Simplify the code by adding the flag to the common flags and removing it everywhere else. Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lore.kernel.org/r/20231219151200.2878271-5-vegard.nossum@oracle.com
126 lines
3.0 KiB
C
126 lines
3.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/* -*- linux-c -*- ------------------------------------------------------- *
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* Prepare the machine for transition to protected mode.
|
|
*/
|
|
|
|
#include "boot.h"
|
|
#include <asm/desc_defs.h>
|
|
#include <asm/segment.h>
|
|
|
|
/*
|
|
* Invoke the realmode switch hook if present; otherwise
|
|
* disable all interrupts.
|
|
*/
|
|
static void realmode_switch_hook(void)
|
|
{
|
|
if (boot_params.hdr.realmode_swtch) {
|
|
asm volatile("lcallw *%0"
|
|
: : "m" (boot_params.hdr.realmode_swtch)
|
|
: "eax", "ebx", "ecx", "edx");
|
|
} else {
|
|
asm volatile("cli");
|
|
outb(0x80, 0x70); /* Disable NMI */
|
|
io_delay();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Disable all interrupts at the legacy PIC.
|
|
*/
|
|
static void mask_all_interrupts(void)
|
|
{
|
|
outb(0xff, 0xa1); /* Mask all interrupts on the secondary PIC */
|
|
io_delay();
|
|
outb(0xfb, 0x21); /* Mask all but cascade on the primary PIC */
|
|
io_delay();
|
|
}
|
|
|
|
/*
|
|
* Reset IGNNE# if asserted in the FPU.
|
|
*/
|
|
static void reset_coprocessor(void)
|
|
{
|
|
outb(0, 0xf0);
|
|
io_delay();
|
|
outb(0, 0xf1);
|
|
io_delay();
|
|
}
|
|
|
|
/*
|
|
* Set up the GDT
|
|
*/
|
|
|
|
struct gdt_ptr {
|
|
u16 len;
|
|
u32 ptr;
|
|
} __attribute__((packed));
|
|
|
|
static void setup_gdt(void)
|
|
{
|
|
/* There are machines which are known to not boot with the GDT
|
|
being 8-byte unaligned. Intel recommends 16 byte alignment. */
|
|
static const u64 boot_gdt[] __attribute__((aligned(16))) = {
|
|
/* CS: code, read/execute, 4 GB, base 0 */
|
|
[GDT_ENTRY_BOOT_CS] = GDT_ENTRY(DESC_CODE32, 0, 0xfffff),
|
|
/* DS: data, read/write, 4 GB, base 0 */
|
|
[GDT_ENTRY_BOOT_DS] = GDT_ENTRY(DESC_DATA32, 0, 0xfffff),
|
|
/* TSS: 32-bit tss, 104 bytes, base 4096 */
|
|
/* We only have a TSS here to keep Intel VT happy;
|
|
we don't actually use it for anything. */
|
|
[GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(DESC_TSS32, 4096, 103),
|
|
};
|
|
/* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead
|
|
of the gdt_ptr contents. Thus, make it static so it will
|
|
stay in memory, at least long enough that we switch to the
|
|
proper kernel GDT. */
|
|
static struct gdt_ptr gdt;
|
|
|
|
gdt.len = sizeof(boot_gdt)-1;
|
|
gdt.ptr = (u32)&boot_gdt + (ds() << 4);
|
|
|
|
asm volatile("lgdtl %0" : : "m" (gdt));
|
|
}
|
|
|
|
/*
|
|
* Set up the IDT
|
|
*/
|
|
static void setup_idt(void)
|
|
{
|
|
static const struct gdt_ptr null_idt = {0, 0};
|
|
asm volatile("lidtl %0" : : "m" (null_idt));
|
|
}
|
|
|
|
/*
|
|
* Actual invocation sequence
|
|
*/
|
|
void go_to_protected_mode(void)
|
|
{
|
|
/* Hook before leaving real mode, also disables interrupts */
|
|
realmode_switch_hook();
|
|
|
|
/* Enable the A20 gate */
|
|
if (enable_a20()) {
|
|
puts("A20 gate not responding, unable to boot...\n");
|
|
die();
|
|
}
|
|
|
|
/* Reset coprocessor (IGNNE#) */
|
|
reset_coprocessor();
|
|
|
|
/* Mask all interrupts in the PIC */
|
|
mask_all_interrupts();
|
|
|
|
/* Actual transition to protected mode... */
|
|
setup_idt();
|
|
setup_gdt();
|
|
protected_mode_jump(boot_params.hdr.code32_start,
|
|
(u32)&boot_params + (ds() << 4));
|
|
}
|