aboutsummaryrefslogtreecommitdiff
path: root/i386/i386at/model_dep.c
diff options
context:
space:
mode:
authorPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
committerPasha <pasha@member.fsf.org>2024-02-20 18:49:50 +0000
commit5e0b8d508ed51004bd836384293be00950ee62c9 (patch)
treee3f16b1aa8b7177032ce3ec429fbad2b1d92a876 /i386/i386at/model_dep.c
downloadgnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.gz
gnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.bz2
init gnumach copy
Diffstat (limited to 'i386/i386at/model_dep.c')
-rw-r--r--i386/i386at/model_dep.c674
1 files changed, 674 insertions, 0 deletions
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
new file mode 100644
index 0000000..edb5b48
--- /dev/null
+++ b/i386/i386at/model_dep.c
@@ -0,0 +1,674 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: model_dep.c
+ * Author: Avadis Tevanian, Jr., Michael Wayne Young
+ *
+ * Copyright (C) 1986, Avadis Tevanian, Jr., Michael Wayne Young
+ *
+ * Basic initialization for I386 - ISA bus machines.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <device/cons.h>
+
+#include <mach/vm_param.h>
+#include <mach/vm_prot.h>
+#include <mach/machine.h>
+#include <mach/machine/multiboot.h>
+#include <mach/xen.h>
+
+#include <kern/assert.h>
+#include <kern/cpu_number.h>
+#include <kern/debug.h>
+#include <kern/mach_clock.h>
+#include <kern/macros.h>
+#include <kern/printf.h>
+#include <kern/startup.h>
+#include <kern/smp.h>
+#include <sys/types.h>
+#include <vm/vm_page.h>
+#include <i386/fpu.h>
+#include <i386/gdt.h>
+#include <i386/ktss.h>
+#include <i386/ldt.h>
+#include <i386/machspl.h>
+#include <i386/mp_desc.h>
+#include <i386/pit.h>
+#include <i386/pmap.h>
+#include <i386/proc_reg.h>
+#include <i386/vm_param.h>
+#include <i386/locore.h>
+#include <i386/model_dep.h>
+#include <i386/smp.h>
+#include <i386/seg.h>
+#include <i386at/acpi_parse_apic.h>
+#include <i386at/autoconf.h>
+#include <i386at/biosmem.h>
+#include <i386at/elf.h>
+#include <i386at/idt.h>
+#include <i386at/int_init.h>
+#include <i386at/kd.h>
+#include <i386at/rtc.h>
+#include <i386at/model_dep.h>
+#include <machine/irq.h>
+
+#ifdef MACH_XEN
+#include <xen/console.h>
+#include <xen/store.h>
+#include <xen/evt.h>
+#include <xen/xen.h>
+#endif /* MACH_XEN */
+
+#if ENABLE_IMMEDIATE_CONSOLE
+#include "immc.h"
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
+
+/* Location of the kernel's symbol table.
+ Both of these are 0 if none is available. */
+#if MACH_KDB
+#include <ddb/db_sym.h>
+#include <i386/db_interface.h>
+
+/* ELF section header */
+static unsigned elf_shdr_num;
+static vm_size_t elf_shdr_size;
+static vm_offset_t elf_shdr_addr;
+static unsigned elf_shdr_shndx;
+
+#endif /* MACH_KDB */
+
+#define RESERVED_BIOS 0x10000
+
+/* A copy of the multiboot info structure passed by the boot loader. */
+#ifdef MACH_XEN
+struct start_info boot_info;
+#ifdef MACH_PSEUDO_PHYS
+unsigned long *mfn_list;
+#if VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
+unsigned long *pfn_list = (void*) PFN_LIST;
+#endif
+#endif /* MACH_PSEUDO_PHYS */
+#if VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
+unsigned long la_shift = VM_MIN_KERNEL_ADDRESS;
+#endif
+#else /* MACH_XEN */
+struct multiboot_raw_info boot_info;
+#endif /* MACH_XEN */
+
+/* Command line supplied to kernel. */
+char *kernel_cmdline = "";
+
+extern char version[];
+
+/* Realmode temporary GDT */
+extern struct pseudo_descriptor gdt_descr_tmp;
+
+/* Realmode relocated jmp */
+extern uint32_t apboot_jmp_offset;
+
+/* If set, reboot the system on ctrl-alt-delete. */
+boolean_t rebootflag = FALSE; /* exported to kdintr */
+
+#ifdef LINUX_DEV
+extern void linux_init(void);
+#endif
+
+/*
+ * Find devices. The system is alive.
+ */
+void machine_init(void)
+{
+ /*
+ * Make more free memory.
+ *
+ * This is particularly important for the Linux drivers which
+ * require available DMA memory.
+ */
+ biosmem_free_usable();
+
+ /*
+ * Set up to use floating point.
+ */
+ init_fpu();
+
+#ifdef MACH_HYP
+ hyp_init();
+#else /* MACH_HYP */
+#if defined(APIC)
+ int err;
+
+ err = acpi_apic_init();
+ if (err) {
+ printf("acpi_apic_init failed with %d\n", err);
+ for (;;);
+ }
+#endif
+#if (NCPUS > 1)
+ smp_init();
+#endif
+#if defined(APIC)
+ ioapic_configure();
+#endif
+ clkstart();
+
+ /*
+ * Initialize the console.
+ */
+ cninit();
+
+#ifdef LINUX_DEV
+ /*
+ * Initialize Linux drivers.
+ */
+ linux_init();
+#endif
+ /*
+ * Find the devices
+ */
+ probeio();
+#endif /* MACH_HYP */
+
+ /*
+ * Get the time
+ */
+ inittodr();
+
+#ifndef MACH_HYP
+ /*
+ * Tell the BIOS not to clear and test memory.
+ */
+ *(unsigned short *)phystokv(0x472) = 0x1234;
+#endif /* MACH_HYP */
+
+#if VM_MIN_KERNEL_ADDRESS == 0
+ /*
+ * Unmap page 0 to trap NULL references.
+ *
+ * Note that this breaks accessing some BIOS areas stored there.
+ */
+ pmap_unmap_page_zero();
+#endif
+
+#if NCPUS > 1
+ /*
+ * Patch the realmode gdt with the correct offset and the first jmp to
+ * protected mode with the correct target.
+ */
+ gdt_descr_tmp.linear_base += apboot_addr;
+ apboot_jmp_offset += apboot_addr;
+
+ /*
+ * Initialize the HPET
+ */
+ hpet_init();
+#endif
+}
+
+/* Conserve power on processor CPU. */
+void machine_idle (int cpu)
+{
+#ifdef MACH_HYP
+ hyp_idle();
+#else /* MACH_HYP */
+ assert (cpu == cpu_number ());
+ asm volatile ("hlt" : : : "memory");
+#endif /* MACH_HYP */
+}
+
+void machine_relax (void)
+{
+ asm volatile ("rep; nop" : : : "memory");
+}
+
+/*
+ * Halt a cpu.
+ */
+void halt_cpu(void)
+{
+#ifdef MACH_HYP
+ hyp_halt();
+#else /* MACH_HYP */
+ asm volatile("cli");
+ while (TRUE)
+ machine_idle (cpu_number ());
+#endif /* MACH_HYP */
+}
+
+/*
+ * Halt the system or reboot.
+ */
+void halt_all_cpus(boolean_t reboot)
+{
+ if (reboot) {
+#ifdef MACH_HYP
+ hyp_reboot();
+#endif /* MACH_HYP */
+ kdreboot();
+ }
+ else {
+ rebootflag = TRUE;
+#ifdef MACH_HYP
+ hyp_halt();
+#endif /* MACH_HYP */
+ printf("Shutdown completed successfully, now in tight loop.\n");
+ printf("You can safely power off the system or hit ctl-alt-del to reboot\n");
+ (void) spl0();
+ }
+ while (TRUE)
+ machine_idle (cpu_number ());
+}
+
+void db_halt_cpu(void)
+{
+ halt_all_cpus(0);
+}
+
+void db_reset_cpu(void)
+{
+ halt_all_cpus(1);
+}
+
+#ifndef MACH_HYP
+
+static void
+register_boot_data(const struct multiboot_raw_info *mbi)
+{
+ struct multiboot_raw_module *mod;
+ struct elf_shdr *shdr;
+ unsigned long tmp;
+ unsigned int i;
+
+ extern char _start[], _end[];
+
+ biosmem_register_boot_data(_kvtophys(&_start), _kvtophys(&_end), FALSE);
+
+ /* cmdline and modules are moved to a safe place by i386at_init. */
+
+ if ((mbi->flags & MULTIBOOT_LOADER_CMDLINE) && (mbi->cmdline != 0)) {
+ biosmem_register_boot_data(mbi->cmdline,
+ mbi->cmdline
+ + strlen((void *)phystokv(mbi->cmdline)) + 1, TRUE);
+ }
+
+ if (mbi->flags & MULTIBOOT_LOADER_MODULES && mbi->mods_count) {
+ i = mbi->mods_count * sizeof(struct multiboot_raw_module);
+ biosmem_register_boot_data(mbi->mods_addr, mbi->mods_addr + i, TRUE);
+
+ tmp = phystokv(mbi->mods_addr);
+
+ for (i = 0; i < mbi->mods_count; i++) {
+ mod = (struct multiboot_raw_module *)tmp + i;
+ if (mod->mod_end != mod->mod_start)
+ biosmem_register_boot_data(mod->mod_start, mod->mod_end, TRUE);
+
+ if (mod->string != 0) {
+ biosmem_register_boot_data(mod->string,
+ mod->string
+ + strlen((void *)phystokv(mod->string)) + 1,
+ TRUE);
+ }
+ }
+ }
+
+ if (mbi->flags & MULTIBOOT_LOADER_SHDR) {
+ tmp = mbi->shdr_num * mbi->shdr_size;
+ if (tmp != 0)
+ biosmem_register_boot_data(mbi->shdr_addr, mbi->shdr_addr + tmp, FALSE);
+
+ tmp = phystokv(mbi->shdr_addr);
+
+ for (i = 0; i < mbi->shdr_num; i++) {
+ shdr = (struct elf_shdr *)(tmp + (i * mbi->shdr_size));
+
+ if ((shdr->type != ELF_SHT_SYMTAB)
+ && (shdr->type != ELF_SHT_STRTAB))
+ continue;
+
+ if (shdr->size != 0)
+ biosmem_register_boot_data(shdr->addr, shdr->addr + shdr->size, FALSE);
+ }
+ }
+}
+
+#endif /* MACH_HYP */
+
+/*
+ * Basic PC VM initialization.
+ * Turns on paging and changes the kernel segments to use high linear addresses.
+ */
+static void
+i386at_init(void)
+{
+ /*
+ * Initialize the PIC prior to any possible call to an spl.
+ */
+#ifndef MACH_HYP
+# ifdef APIC
+ picdisable();
+# else
+ picinit();
+# endif
+#else /* MACH_HYP */
+ hyp_intrinit();
+#endif /* MACH_HYP */
+ spl_init = 1;
+
+ /*
+ * Read memory map and load it into the physical page allocator.
+ */
+#ifdef MACH_HYP
+ biosmem_xen_bootstrap();
+#else /* MACH_HYP */
+ register_boot_data((struct multiboot_raw_info *) &boot_info);
+ biosmem_bootstrap((struct multiboot_raw_info *) &boot_info);
+#endif /* MACH_HYP */
+
+#ifdef MACH_XEN
+ kernel_cmdline = (char*) boot_info.cmd_line;
+#else /* MACH_XEN */
+ vm_offset_t addr;
+
+ /* Copy content pointed by boot_info before losing access to it when it
+ * is too far in physical memory.
+ * Also avoids leaving them in precious areas such as DMA memory. */
+ if (boot_info.flags & MULTIBOOT_CMDLINE) {
+ int len = strlen ((char*)phystokv(boot_info.cmdline)) + 1;
+ if (! init_alloc_aligned(round_page(len), &addr))
+ panic("could not allocate memory for multiboot command line");
+ kernel_cmdline = (char*) phystokv(addr);
+ memcpy(kernel_cmdline, (void *)phystokv(boot_info.cmdline), len);
+ boot_info.cmdline = addr;
+ }
+
+ if (boot_info.flags & MULTIBOOT_MODS && boot_info.mods_count) {
+ struct multiboot_raw_module *m;
+ int i;
+
+ if (! init_alloc_aligned(
+ round_page(boot_info.mods_count * sizeof(*m)), &addr))
+ panic("could not allocate memory for multiboot modules");
+ m = (void*) phystokv(addr);
+ memcpy(m, (void*) phystokv(boot_info.mods_addr), boot_info.mods_count * sizeof(*m));
+ boot_info.mods_addr = addr;
+
+ for (i = 0; i < boot_info.mods_count; i++) {
+ vm_size_t size = m[i].mod_end - m[i].mod_start;
+ if (! init_alloc_aligned(round_page(size), &addr))
+ panic("could not allocate memory for multiboot "
+ "module %d", i);
+ memcpy((void*) phystokv(addr), (void*) phystokv(m[i].mod_start), size);
+ m[i].mod_start = addr;
+ m[i].mod_end = addr + size;
+
+ size = strlen((char*) phystokv(m[i].string)) + 1;
+ if (! init_alloc_aligned(round_page(size), &addr))
+ panic("could not allocate memory for multiboot "
+ "module command line %d", i);
+ memcpy((void*) phystokv(addr), (void*) phystokv(m[i].string), size);
+ m[i].string = addr;
+ }
+ }
+#endif /* MACH_XEN */
+
+ /*
+ * Initialize kernel physical map, mapping the
+ * region from loadpt to avail_start.
+ * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
+ * XXX make the BIOS page (page 0) read-only.
+ */
+ pmap_bootstrap();
+
+ /*
+ * Load physical segments into the VM system.
+ * The early allocation functions become unusable after
+ * this point.
+ */
+ biosmem_setup();
+
+ pmap_make_temporary_mapping();
+
+#ifndef MACH_HYP
+ /* Turn paging on.
+ * Also set the WP bit so that on 486 or better processors
+ * page-level write protection works in kernel mode.
+ */
+ set_cr0(get_cr0() | CR0_PG | CR0_WP);
+ set_cr0(get_cr0() & ~(CR0_CD | CR0_NW));
+ if (CPU_HAS_FEATURE(CPU_FEATURE_PGE))
+ set_cr4(get_cr4() | CR4_PGE);
+#endif /* MACH_HYP */
+ flush_instr_queue();
+#ifdef MACH_PV_PAGETABLES
+ pmap_clear_bootstrap_pagetable((void *)boot_info.pt_base);
+#endif /* MACH_PV_PAGETABLES */
+
+ /*
+ * Initialize and activate the real i386 protected-mode structures.
+ */
+ gdt_init();
+ idt_init();
+#ifndef MACH_HYP
+ int_init();
+#endif /* MACH_HYP */
+ ldt_init();
+ ktss_init();
+
+#ifndef MACH_XEN
+ init_percpu(0);
+#endif
+#if NCPUS > 1
+ /* Initialize SMP structures in the master processor */
+ mp_desc_init(0);
+#endif // NCPUS
+
+ pmap_remove_temporary_mapping();
+
+#ifdef MACH_XEN
+ hyp_p2m_init();
+#endif /* MACH_XEN */
+
+ interrupt_stack_alloc();
+}
+
+/*
+ * C boot entrypoint - called by boot_entry in boothdr.S.
+ * Running in flat mode, but without paging yet.
+ */
+void c_boot_entry(vm_offset_t bi)
+{
+#if ENABLE_IMMEDIATE_CONSOLE
+ romputc = immc_romputc;
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
+
+ /* Stash the boot_image_info pointer. */
+ boot_info = *(typeof(boot_info)*)phystokv(bi);
+ int cpu_type;
+
+ /* Before we do _anything_ else, print the hello message.
+ If there are no initialized console devices yet,
+ it will be stored and printed at the first opportunity. */
+ printf("%s", version);
+ printf("\n");
+
+#ifdef MACH_XEN
+ printf("Running on %s.\n", boot_info.magic);
+ if (boot_info.flags & SIF_PRIVILEGED)
+ panic("Mach can't run as dom0.");
+#ifdef MACH_PSEUDO_PHYS
+ mfn_list = (void*)boot_info.mfn_list;
+#endif
+#else /* MACH_XEN */
+
+#if MACH_KDB
+ /*
+ * Locate the kernel's symbol table, if the boot loader provided it.
+ * We need to do this before i386at_init()
+ * so that the symbol table's memory won't be stomped on.
+ */
+ if ((boot_info.flags & MULTIBOOT_ELF_SHDR)
+ && boot_info.shdr_num)
+ {
+ elf_shdr_num = boot_info.shdr_num;
+ elf_shdr_size = boot_info.shdr_size;
+ elf_shdr_addr = (vm_offset_t)phystokv(boot_info.shdr_addr);
+ elf_shdr_shndx = boot_info.shdr_strndx;
+
+ printf("ELF section header table at %08" PRIxPTR "\n", elf_shdr_addr);
+ }
+#endif /* MACH_KDB */
+#endif /* MACH_XEN */
+
+ cpu_type = discover_x86_cpu_type ();
+
+ /*
+ * Do basic VM initialization
+ */
+ i386at_init();
+
+#if MACH_KDB
+ /*
+ * Initialize the kernel debugger's kernel symbol table.
+ */
+ if (elf_shdr_num)
+ {
+ elf_db_sym_init(elf_shdr_num,elf_shdr_size,
+ elf_shdr_addr, elf_shdr_shndx,
+ "mach", NULL);
+ }
+#endif /* MACH_KDB */
+
+ machine_slot[0].is_cpu = TRUE;
+ machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386;
+
+#if defined(__x86_64__) && !defined(USER32)
+ machine_slot[0].cpu_type = CPU_TYPE_X86_64;
+#else
+ switch (cpu_type)
+ {
+ default:
+ printf("warning: unknown cpu type %d, assuming i386\n", cpu_type);
+ case 3:
+ machine_slot[0].cpu_type = CPU_TYPE_I386;
+ break;
+ case 4:
+ machine_slot[0].cpu_type = CPU_TYPE_I486;
+ break;
+ case 5:
+ machine_slot[0].cpu_type = CPU_TYPE_PENTIUM;
+ break;
+ case 6:
+ case 15:
+ machine_slot[0].cpu_type = CPU_TYPE_PENTIUMPRO;
+ break;
+ }
+#endif
+
+ /*
+ * Start the system.
+ */
+ setup_main();
+
+}
+
+#include <mach/vm_prot.h>
+#include <vm/pmap.h>
+#include <mach/time_value.h>
+
+vm_offset_t
+timemmap(dev_t dev, vm_offset_t off, vm_prot_t prot)
+{
+ extern time_value_t *mtime;
+
+ if (prot & VM_PROT_WRITE) return (-1);
+
+ return (i386_btop(pmap_extract(pmap_kernel(), (vm_offset_t) mtime)));
+}
+
+void
+startrtclock(void)
+{
+#ifdef APIC
+ unmask_irq(timer_pin);
+ calibrate_lapic_timer();
+ if (cpu_number() != 0) {
+ lapic_enable_timer();
+ }
+#else
+ clkstart();
+#ifndef MACH_HYP
+ unmask_irq(0);
+#endif
+#endif
+}
+
+void
+inittodr(void)
+{
+ time_value64_t new_time;
+ uint64_t newsecs;
+
+ (void) readtodc(&newsecs);
+ new_time.seconds = newsecs;
+ new_time.nanoseconds = 0;
+
+ {
+ spl_t s = splhigh();
+ time = new_time;
+ splx(s);
+ }
+}
+
+void
+resettodr(void)
+{
+ writetodc();
+}
+
+boolean_t
+init_alloc_aligned(vm_size_t size, vm_offset_t *addrp)
+{
+ *addrp = biosmem_bootalloc(vm_page_atop(vm_page_round(size)));
+
+ if (*addrp == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Grab a physical page:
+ the standard memory allocation mechanism
+ during system initialization. */
+vm_offset_t
+pmap_grab_page(void)
+{
+ vm_offset_t addr;
+ if (!init_alloc_aligned(PAGE_SIZE, &addr))
+ panic("Not enough memory to initialize Mach");
+ return addr;
+}