aboutsummaryrefslogtreecommitdiff
path: root/i386/i386at
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
downloadgnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.gz
gnumach-riscv-5e0b8d508ed51004bd836384293be00950ee62c9.tar.bz2
init gnumach copy
Diffstat (limited to 'i386/i386at')
-rw-r--r--i386/i386at/acpi_parse_apic.c650
-rw-r--r--i386/i386at/acpi_parse_apic.h201
-rw-r--r--i386/i386at/autoconf.c149
-rw-r--r--i386/i386at/autoconf.h43
-rw-r--r--i386/i386at/biosmem.c1070
-rw-r--r--i386/i386at/biosmem.h109
-rw-r--r--i386/i386at/boothdr.S179
-rw-r--r--i386/i386at/com.c900
-rw-r--r--i386/i386at/com.h86
-rw-r--r--i386/i386at/comreg.h139
-rw-r--r--i386/i386at/conf.c172
-rw-r--r--i386/i386at/cons_conf.c63
-rw-r--r--i386/i386at/cram.h86
-rw-r--r--i386/i386at/disk.h89
-rw-r--r--i386/i386at/elf.h61
-rw-r--r--i386/i386at/i8250.h134
-rw-r--r--i386/i386at/idt.h53
-rw-r--r--i386/i386at/immc.c134
-rw-r--r--i386/i386at/immc.h31
-rw-r--r--i386/i386at/int_init.c82
-rw-r--r--i386/i386at/int_init.h35
-rw-r--r--i386/i386at/interrupt.S142
-rw-r--r--i386/i386at/ioapic.c463
-rw-r--r--i386/i386at/kd.c3059
-rw-r--r--i386/i386at/kd.h744
-rw-r--r--i386/i386at/kd_event.c392
-rw-r--r--i386/i386at/kd_event.h62
-rw-r--r--i386/i386at/kd_mouse.c800
-rw-r--r--i386/i386at/kd_mouse.h72
-rw-r--r--i386/i386at/kd_queue.c109
-rw-r--r--i386/i386at/kd_queue.h86
-rw-r--r--i386/i386at/kdasm.S145
-rw-r--r--i386/i386at/kdsoft.h209
-rw-r--r--i386/i386at/lpr.c285
-rw-r--r--i386/i386at/lpr.h66
-rw-r--r--i386/i386at/mem.c42
-rw-r--r--i386/i386at/mem.h24
-rw-r--r--i386/i386at/model_dep.c674
-rw-r--r--i386/i386at/model_dep.h39
-rw-r--r--i386/i386at/pic_isa.c56
-rw-r--r--i386/i386at/rtc.c242
-rw-r--r--i386/i386at/rtc.h143
42 files changed, 12320 insertions, 0 deletions
diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
new file mode 100644
index 0000000..1cfc179
--- /dev/null
+++ b/i386/i386at/acpi_parse_apic.c
@@ -0,0 +1,650 @@
+/* acpi_parse_apic.h - ACPI-MADT table parser. Source file
+ Copyright (C) 2018 Juan Bosco Garcia
+ Copyright (C) 2019 2020 Almudena Garcia Jurado-Centurion
+ Written by Juan Bosco Garcia and Almudena Garcia Jurado-Centurion
+
+ This file is part of Min_SMP.
+
+ Min_SMP 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, or (at your option)
+ any later version.
+
+ Min_SMP 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h> /* memcmp, memcpy... */
+
+#include <stdint.h> /* uint16_t, uint32_t... */
+
+#include <mach/machine.h> /* machine_slot */
+
+#include <kern/printf.h> /* printf */
+#include <kern/debug.h>
+#include <i386/vm_param.h> /* phystokv */
+#include <i386/apic.h> /* lapic, ioapic... */
+#include <i386at/acpi_parse_apic.h>
+#include <vm/vm_kern.h>
+
+static struct acpi_apic *apic_madt = NULL;
+unsigned lapic_addr;
+uint32_t *hpet_addr;
+
+/*
+ * acpi_print_info: shows by screen the ACPI's rsdp and rsdt virtual address
+ * and the number of entries stored in RSDT table.
+ *
+ * Receives as input the references of RSDP and RSDT tables,
+ * and the number of entries stored in RSDT.
+ */
+void
+acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n)
+{
+
+ printf("ACPI:\n");
+ printf(" rsdp = 0x%lx\n", rsdp);
+ printf(" rsdt/xsdt = 0x%p (n = %d)\n", rsdt, acpi_rsdt_n);
+}
+
+/*
+ * acpi_checksum: calculates the checksum of an ACPI table.
+ * Receives as input the virtual address of the table.
+ *
+ * Returns 0 if success, other value if error.
+ */
+static uint8_t
+acpi_checksum(void *addr, uint32_t length)
+{
+ uint8_t *bytes = addr;
+ uint8_t checksum = 0;
+ unsigned int i;
+
+ /* Sum all bytes of addr */
+ for (i = 0; i < length; i++)
+ checksum += bytes[i];
+
+ return checksum;
+}
+
+/*
+ * acpi_check_signature: check if a signature match with the signature of its table.
+ *
+ * Receive as parameter both signatures: table signature, the signature which needs to check,
+ * and real signature, the genuine signature of the table.
+ *
+ * Return 0 if success, other if error.
+ */
+
+static int
+acpi_check_signature(const uint8_t table_signature[], const char *real_signature, uint8_t length)
+{
+ return memcmp(table_signature, real_signature, length);
+}
+
+
+/*
+ * acpi_check_rsdp:
+ * check if the RDSP "candidate" table is the real RSDP table.
+ *
+ * Compare the table signature with the ACPI signature for this table
+ * and check is the checksum is correct.
+ *
+ * Receives as input the reference of RSDT table.
+ *
+ * Preconditions: RSDP pointer must not be NULL.
+ *
+ * Returns 1 if ACPI 1.0 and sets sdt_base
+ * Returns 2 if ACPI >= 2.0 and sets sdt_base
+ */
+static int8_t
+acpi_check_rsdp(struct acpi_rsdp2 *rsdp, phys_addr_t *sdt_base)
+{
+ int is_rsdp;
+ uint8_t cksum;
+
+ /* Check if rsdp signature match with the ACPI RSDP signature. */
+ is_rsdp = acpi_check_signature(rsdp->v1.signature, ACPI_RSDP_SIG, 8*sizeof(uint8_t));
+
+ if (is_rsdp != ACPI_SUCCESS)
+ return ACPI_BAD_SIGNATURE;
+
+ if (rsdp->v1.revision == 0) {
+ // ACPI 1.0
+ *sdt_base = rsdp->v1.rsdt_addr;
+ printf("ACPI v1.0\n");
+ cksum = acpi_checksum((void *)(&rsdp->v1), sizeof(struct acpi_rsdp));
+
+ if (cksum != 0)
+ return ACPI_BAD_CHECKSUM;
+
+ return 1;
+
+ } else if (rsdp->v1.revision == 2) {
+ // ACPI >= 2.0
+ *sdt_base = rsdp->xsdt_addr;
+ printf("ACPI >= v2.0\n");
+ cksum = acpi_checksum((void *)rsdp, sizeof(struct acpi_rsdp2));
+
+ if (cksum != 0)
+ return ACPI_BAD_CHECKSUM;
+
+ return 2;
+ }
+
+ return ACPI_NO_RSDP;
+}
+
+/*
+ * acpi_check_rsdp_align: check if the RSDP address is aligned.
+ * Preconditions: The address must not be NULL
+ *
+ * Returns ACPI_SUCCESS (0) if success, ACPI_BAD_ALIGN if error
+ */
+
+static int8_t
+acpi_check_rsdp_align(void *addr)
+{
+ /* check alignment. */
+ if ((uintptr_t)addr & (ACPI_RSDP_ALIGN-1))
+ return ACPI_BAD_ALIGN;
+
+ return ACPI_SUCCESS;
+}
+
+/*
+ * acpi_search_rsdp: search the rsdp table in a memory range.
+ *
+ * Receives as input the initial virtual address, and the lenght
+ * of memory range.
+ *
+ * Preconditions: The start address (addr) must be aligned.
+ *
+ * Returns the physical address of rsdp structure if success, 0 if failure.
+ */
+static phys_addr_t
+acpi_search_rsdp(void *addr, uint32_t length, int *is_64bit)
+{
+ void *end;
+ int version = 0;
+ phys_addr_t sdt_base = 0;
+
+ /* Search RDSP in memory space between addr and addr+lenght. */
+ for (end = addr+length; addr < end; addr += ACPI_RSDP_ALIGN) {
+
+ /* Check if the current memory block stores the RDSP. */
+ if ((addr != NULL) && ((version = acpi_check_rsdp(addr, &sdt_base)) > 0)) {
+ /* If yes, return RSDT/XSDT address */
+ *is_64bit = (version == 2);
+ return sdt_base;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * acpi_get_rsdp: tries to find the RSDP table,
+ * searching It in many memory ranges, as It's written in ACPI Specification.
+ *
+ * Returns the reference to RDSP structure if success, 0 if failure.
+ */
+static phys_addr_t
+acpi_get_rsdp(int *is_64bit)
+{
+ uint16_t *start = 0;
+ phys_addr_t base = 0;
+ phys_addr_t rsdp = 0;
+
+ /* EDBA start address. */
+ start = (uint16_t*) phystokv(0x040e);
+ base = phystokv((*start) << 4); /* address = paragraph number * 16 */
+
+ /* check alignment. */
+ if (acpi_check_rsdp_align((void *)base) == ACPI_BAD_ALIGN)
+ return 0;
+ rsdp = acpi_search_rsdp((void *)base, 1024, is_64bit);
+
+ if (rsdp == 0) {
+ /* If RSDP isn't in EDBA, search in the BIOS read-only memory space between 0E0000h and 0FFFFFh */
+ rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 - 0x0e0000, is_64bit);
+ }
+
+ return rsdp;
+}
+
+/*
+ * acpi_get_rsdt: Get RSDT table reference from RSDP entries.
+ *
+ * Receives as input a reference for RSDP table
+ * and a reference to store the number of entries of RSDT.
+ *
+ * Returns the reference to RSDT table if success, NULL if error.
+ */
+static struct acpi_rsdt*
+acpi_get_rsdt(phys_addr_t rsdp_phys, int* acpi_rsdt_n)
+{
+ struct acpi_rsdt *rsdt = NULL;
+ int signature_check;
+
+ rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdp_phys, sizeof(struct acpi_rsdt), VM_PROT_READ);
+
+ /* Check if the RSDT mapping is fine. */
+ if (rsdt == NULL)
+ return NULL;
+
+ /* Check is rsdt signature is equals to ACPI RSDT signature. */
+ signature_check = acpi_check_signature(rsdt->header.signature, ACPI_RSDT_SIG,
+ 4*sizeof(uint8_t));
+
+ if (signature_check != ACPI_SUCCESS)
+ return NULL;
+
+ /* Calculated number of elements stored in rsdt. */
+ *acpi_rsdt_n = (rsdt->header.length - sizeof(rsdt->header))
+ / sizeof(rsdt->entry[0]);
+
+ return rsdt;
+}
+
+/*
+ * acpi_get_xsdt: Get XSDT table reference from RSDPv2 entries.
+ *
+ * Receives as input a reference for RSDPv2 table
+ * and a reference to store the number of entries of XSDT.
+ *
+ * Returns the reference to XSDT table if success, NULL if error.
+ */
+static struct acpi_xsdt*
+acpi_get_xsdt(phys_addr_t rsdp_phys, int* acpi_xsdt_n)
+{
+ struct acpi_xsdt *xsdt = NULL;
+ int signature_check;
+
+ xsdt = (struct acpi_xsdt*) kmem_map_aligned_table(rsdp_phys, sizeof(struct acpi_xsdt), VM_PROT_READ);
+
+ /* Check if the RSDT mapping is fine. */
+ if (xsdt == NULL)
+ return NULL;
+
+ /* Check is rsdt signature is equals to ACPI RSDT signature. */
+ signature_check = acpi_check_signature(xsdt->header.signature, ACPI_XSDT_SIG,
+ 4*sizeof(uint8_t));
+
+ if (signature_check != ACPI_SUCCESS)
+ return NULL;
+
+ /* Calculated number of elements stored in rsdt. */
+ *acpi_xsdt_n = (xsdt->header.length - sizeof(xsdt->header))
+ / sizeof(xsdt->entry[0]);
+
+ return xsdt;
+}
+
+/*
+ * acpi_get_apic: get MADT/APIC table from RSDT entries.
+ *
+ * Receives as input the RSDT initial address,
+ * and the number of entries of RSDT table.
+ *
+ * Returns a reference to APIC/MADT table if success, NULL if failure.
+ * Also sets hpet_addr to base address of HPET.
+ */
+static struct acpi_apic*
+acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
+{
+ struct acpi_dhdr *descr_header;
+ struct acpi_apic *madt = NULL;
+ int check_signature;
+ uint64_t map_addr;
+
+ /* Search APIC entries in rsdt table. */
+ for (int i = 0; i < acpi_rsdt_n; i++) {
+ descr_header = (struct acpi_dhdr*) kmem_map_aligned_table(rsdt->entry[i], sizeof(struct acpi_dhdr),
+ VM_PROT_READ);
+
+ /* Check if the entry is a MADT */
+ check_signature = acpi_check_signature(descr_header->signature, ACPI_APIC_SIG, 4*sizeof(uint8_t));
+ if (check_signature == ACPI_SUCCESS)
+ madt = (struct acpi_apic*) descr_header;
+
+ /* Check if the entry is a HPET */
+ check_signature = acpi_check_signature(descr_header->signature, ACPI_HPET_SIG, 4*sizeof(uint8_t));
+ if (check_signature == ACPI_SUCCESS) {
+ map_addr = ((struct acpi_hpet *)descr_header)->address.addr64;
+ assert (map_addr != 0);
+ hpet_addr = (uint32_t *)kmem_map_aligned_table(map_addr, 1024, VM_PROT_READ | VM_PROT_WRITE);
+ printf("HPET at physical address 0x%llx\n", map_addr);
+ }
+ }
+
+ return madt;
+}
+
+/*
+ * acpi_get_apic2: get MADT/APIC table from XSDT entries.
+ *
+ * Receives as input the XSDT initial address,
+ * and the number of entries of XSDT table.
+ *
+ * Returns a reference to APIC/MADT table if success, NULL if failure.
+ * Also sets hpet_addr to base address of HPET.
+ */
+static struct acpi_apic*
+acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n)
+{
+ struct acpi_dhdr *descr_header;
+ struct acpi_apic *madt = NULL;
+ int check_signature;
+ uint64_t map_addr;
+
+ /* Search APIC entries in rsdt table. */
+ for (int i = 0; i < acpi_xsdt_n; i++) {
+ descr_header = (struct acpi_dhdr*) kmem_map_aligned_table(xsdt->entry[i], sizeof(struct acpi_dhdr),
+ VM_PROT_READ);
+
+ /* Check if the entry is an APIC. */
+ check_signature = acpi_check_signature(descr_header->signature, ACPI_APIC_SIG, 4*sizeof(uint8_t));
+ if (check_signature == ACPI_SUCCESS)
+ madt = (struct acpi_apic *)descr_header;
+
+ /* Check if the entry is a HPET. */
+ check_signature = acpi_check_signature(descr_header->signature, ACPI_HPET_SIG, 4*sizeof(uint8_t));
+ if (check_signature == ACPI_SUCCESS) {
+ map_addr = ((struct acpi_hpet *)descr_header)->address.addr64;
+ assert (map_addr != 0);
+ hpet_addr = (uint32_t *)kmem_map_aligned_table(map_addr, 1024, VM_PROT_READ | VM_PROT_WRITE);
+ printf("HPET at physical address 0x%llx\n", map_addr);
+ }
+ }
+
+ return madt;
+}
+
+/*
+ * acpi_add_lapic: add a new Local APIC to cpu_to_lapic array
+ * and increase the number of cpus.
+ *
+ * Receives as input the Local APIC entry in MADT/APIC table.
+ */
+static void
+acpi_apic_add_lapic(struct acpi_apic_lapic *lapic_entry)
+{
+ /* If cpu flag is correct */
+ if (lapic_entry->flags & 0x1) {
+ /* Add cpu to processors' list. */
+ apic_add_cpu(lapic_entry->apic_id);
+ }
+
+}
+
+/*
+ * apic_add_ioapic: add a new IOAPIC to IOAPICS array
+ * and increase the number of IOAPIC.
+ *
+ * Receives as input the IOAPIC entry in MADT/APIC table.
+ */
+
+static void
+acpi_apic_add_ioapic(struct acpi_apic_ioapic *ioapic_entry)
+{
+ IoApicData io_apic;
+
+ /* Fill IOAPIC structure with its main fields */
+ io_apic.apic_id = ioapic_entry->apic_id;
+ io_apic.addr = ioapic_entry->addr;
+ io_apic.gsi_base = ioapic_entry->gsi_base;
+ io_apic.ioapic = (ApicIoUnit *)kmem_map_aligned_table(ioapic_entry->addr,
+ sizeof(ApicIoUnit),
+ VM_PROT_READ | VM_PROT_WRITE);
+ io_apic.ioapic->select.r = APIC_IO_VERSION;
+ io_apic.ngsis = ((io_apic.ioapic->window.r >> APIC_IO_ENTRIES_SHIFT) & 0xff) + 1;
+
+ /* Insert IOAPIC in the list. */
+ apic_add_ioapic(io_apic);
+}
+
+
+/*
+ * apic_add_ioapic: add a new IOAPIC to IOAPICS list
+ * and increase the number of IOAPIC.
+ *
+ * Receives as input the IOAPIC entry in MADT/APIC table.
+ */
+
+static void
+acpi_apic_add_irq_override(struct acpi_apic_irq_override* irq_override)
+{
+ IrqOverrideData irq_over;
+
+ /* Fills IRQ override structure with its fields */
+ irq_over.bus = irq_override->bus;
+ irq_over.irq = irq_override->irq;
+ irq_over.gsi = irq_override->gsi;
+ irq_over.flags = irq_override->flags;
+
+ /* Insert IRQ override in the list */
+ apic_add_irq_override(irq_over);
+}
+
+
+/*
+ * apic_parse_table: parse the MADT/APIC table.
+ *
+ * Read the APIC/MADT table entry to entry,
+ * registering the APIC structures (Local APIC, IOAPIC or IRQ override) entries in their lists.
+ */
+
+static int
+acpi_apic_parse_table(struct acpi_apic *apic)
+{
+ struct acpi_apic_dhdr *apic_entry = NULL;
+ vm_offset_t end = 0;
+ uint8_t numcpus = 1;
+
+ /* Get the address of first APIC entry */
+ apic_entry = (struct acpi_apic_dhdr*) apic->entry;
+
+ /* Get the end address of APIC table */
+ end = (vm_offset_t) apic + apic->header.length;
+
+ printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
+
+ /* Initialize number of cpus */
+ numcpus = apic_get_numcpus();
+
+ /* Search in APIC entry. */
+ while ((vm_offset_t)apic_entry < end) {
+ struct acpi_apic_lapic *lapic_entry;
+ struct acpi_apic_ioapic *ioapic_entry;
+ struct acpi_apic_irq_override *irq_override_entry;
+
+ printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
+ /* Check entry type. */
+ switch(apic_entry->type) {
+
+ /* If APIC entry is a CPU's Local APIC. */
+ case ACPI_APIC_ENTRY_LAPIC:
+ if(numcpus < NCPUS) {
+ /* Store Local APIC data. */
+ lapic_entry = (struct acpi_apic_lapic*) apic_entry;
+ acpi_apic_add_lapic(lapic_entry);
+ }
+ break;
+
+ /* If APIC entry is an IOAPIC. */
+ case ACPI_APIC_ENTRY_IOAPIC:
+
+ /* Store IOAPIC data. */
+ ioapic_entry = (struct acpi_apic_ioapic*) apic_entry;
+ acpi_apic_add_ioapic(ioapic_entry);
+
+ break;
+
+ /* If APIC entry is a IRQ Override. */
+ case ACPI_APIC_ENTRY_IRQ_OVERRIDE:
+
+ /* Store IRQ Override data. */
+ irq_override_entry = (struct acpi_apic_irq_override*) apic_entry;
+ acpi_apic_add_irq_override(irq_override_entry);
+ break;
+
+ /* FIXME: There is another unhandled case */
+ default:
+ printf("Unhandled APIC entry type 0x%x\n", apic_entry->type);
+ break;
+ }
+
+ /* Get next APIC entry. */
+ apic_entry = (struct acpi_apic_dhdr*)((vm_offset_t) apic_entry
+ + apic_entry->length);
+
+ /* Update number of cpus. */
+ numcpus = apic_get_numcpus();
+ }
+
+ return ACPI_SUCCESS;
+}
+
+
+/*
+ * acpi_apic_setup: parses the APIC/MADT table, to find the Local APIC and IOAPIC structures
+ * and the common address for Local APIC.
+ *
+ * Receives as input a reference for APIC/MADT table.
+ * Returns 0 if success.
+ *
+ * Fills the cpu_to_lapic and ioapics array, indexed by Kernel ID
+ * with a relationship between Kernel ID and APIC ID,
+ * and map the Local APIC common address, to fill the lapic reference.
+ *
+ * Precondition: The APIC pointer must not be NULL
+ */
+
+static int
+acpi_apic_setup(struct acpi_apic *apic)
+{
+ ApicLocalUnit* lapic_unit;
+ uint8_t ncpus, nioapics;
+
+ /* map common lapic address */
+ lapic_addr = apic->lapic_addr;
+ lapic_unit = kmem_map_aligned_table(apic->lapic_addr, sizeof(ApicLocalUnit),
+ VM_PROT_READ | VM_PROT_WRITE);
+
+ if (lapic_unit == NULL)
+ return ACPI_NO_LAPIC;
+
+ apic_lapic_init(lapic_unit);
+ acpi_apic_parse_table(apic);
+
+ ncpus = apic_get_numcpus();
+ nioapics = apic_get_num_ioapics();
+
+ if (ncpus == 0 || nioapics == 0 || ncpus > NCPUS)
+ return ACPI_APIC_FAILURE;
+
+ /* Refit the apic-cpu array. */
+ if(ncpus < NCPUS) {
+ int refit = apic_refit_cpulist();
+ if (refit != 0)
+ return ACPI_FIT_FAILURE;
+ }
+
+ apic_generate_cpu_id_lut();
+
+ return ACPI_SUCCESS;
+}
+
+/*
+ * acpi_apic_init: find the MADT/APIC table in ACPI tables
+ * and parses It to find Local APIC and IOAPIC structures.
+ * Each Local APIC stores the info and control structores for a cpu.
+ * The IOAPIC controls the communication of the processors with the I/O devices.
+ *
+ * Returns 0 if success, -1 if error.
+ */
+int
+acpi_apic_init(void)
+{
+ phys_addr_t rsdp = 0;
+ struct acpi_rsdt *rsdt = 0;
+ struct acpi_xsdt *xsdt = 0;
+ int acpi_rsdt_n;
+ int ret_acpi_setup;
+ int apic_init_success = 0;
+ int is_64bit = 0;
+ uint8_t checksum;
+
+ /* Try to get the RSDP physical address. */
+ rsdp = acpi_get_rsdp(&is_64bit);
+ if (rsdp == 0)
+ return ACPI_NO_RSDP;
+
+ if (!is_64bit) {
+ /* Try to get the RSDT pointer. */
+ rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
+ if (rsdt == NULL)
+ return ACPI_NO_RSDT;
+
+ checksum = acpi_checksum((void *)rsdt, rsdt->header.length);
+ if (checksum != 0)
+ return ACPI_BAD_CHECKSUM;
+
+ /* Try to get the APIC table pointer. */
+ apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
+ if (apic_madt == NULL)
+ return ACPI_NO_APIC;
+
+ checksum = acpi_checksum((void *)apic_madt, apic_madt->header.length);
+ if (checksum != 0)
+ return ACPI_BAD_CHECKSUM;
+
+ /* Print the ACPI tables addresses. */
+ acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
+
+ } else {
+ /* Try to get the XSDT pointer. */
+ xsdt = acpi_get_xsdt(rsdp, &acpi_rsdt_n);
+ if (xsdt == NULL)
+ return ACPI_NO_RSDT;
+
+ checksum = acpi_checksum((void *)xsdt, xsdt->header.length);
+ if (checksum != 0)
+ return ACPI_BAD_CHECKSUM;
+
+ /* Try to get the APIC table pointer. */
+ apic_madt = acpi_get_apic2(xsdt, acpi_rsdt_n);
+ if (apic_madt == NULL)
+ return ACPI_NO_APIC;
+
+ checksum = acpi_checksum((void *)apic_madt, apic_madt->header.length);
+ if (checksum != 0)
+ return ACPI_BAD_CHECKSUM;
+
+ /* Print the ACPI tables addresses. */
+ acpi_print_info(rsdp, xsdt, acpi_rsdt_n);
+ }
+
+ apic_init_success = apic_data_init();
+ if (apic_init_success != ACPI_SUCCESS)
+ return ACPI_APIC_FAILURE;
+
+ /*
+ * Starts the parsing of APIC table, to find the APIC structures.
+ * and enumerate them. This function also find the common Local APIC address.
+ */
+ ret_acpi_setup = acpi_apic_setup(apic_madt);
+ if (ret_acpi_setup != ACPI_SUCCESS)
+ return ret_acpi_setup;
+
+ /* Prints a table with the list of each cpu and each IOAPIC with its APIC ID. */
+ apic_print_info();
+
+ return ACPI_SUCCESS;
+}
diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h
new file mode 100644
index 0000000..85e0117
--- /dev/null
+++ b/i386/i386at/acpi_parse_apic.h
@@ -0,0 +1,201 @@
+/* acpi_parse_apic.h - ACPI-MADT table parser. Header file
+ Copyright (C) 2018 Juan Bosco Garcia
+ Copyright (C) 2019 2020 Almudena Garcia Jurado-Centurion
+ Written by Juan Bosco Garcia and Almudena Garcia Jurado-Centurion
+
+ This file is part of Min_SMP.
+
+ Min_SMP 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, or (at your option)
+ any later version.
+
+ Min_SMP 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef __ACPI_H__
+#define __ACPI_H__
+
+#include <stdint.h>
+
+enum ACPI_RETURN {
+ ACPI_BAD_CHECKSUM = -1,
+ ACPI_BAD_ALIGN = -2,
+ ACPI_NO_RSDP = -3,
+ ACPI_NO_RSDT = -4,
+ ACPI_BAD_SIGNATURE = -5,
+ ACPI_NO_APIC = -6,
+ ACPI_NO_LAPIC = -7,
+ ACPI_APIC_FAILURE = -8,
+ ACPI_FIT_FAILURE = -9,
+ ACPI_SUCCESS = 0,
+};
+
+#define ACPI_RSDP_ALIGN 16
+#define ACPI_RSDP_SIG "RSD PTR "
+
+struct acpi_rsdp {
+ uint8_t signature[8];
+ uint8_t checksum;
+ uint8_t oem_id[6];
+ uint8_t revision;
+ uint32_t rsdt_addr;
+} __attribute__((__packed__));
+
+struct acpi_rsdp2 {
+ struct acpi_rsdp v1;
+ uint32_t length;
+ uint64_t xsdt_addr;
+ uint8_t checksum;
+ uint8_t reserved[3];
+} __attribute__((__packed__));
+
+/*
+ * RSDT Entry Header
+ *
+ * Header which stores the descriptors of tables pointed from RDSP's Entry Field
+ * Includes the signature of the table, to identify each table.
+ *
+ * In MADT, the signature is 'APIC'.
+ */
+struct acpi_dhdr {
+ uint8_t signature[4];
+ uint32_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ uint8_t oem_id[6];
+ uint8_t oem_table_id[8];
+ uint32_t oem_revision;
+ uint8_t creator_id[4];
+ uint32_t creator_revision;
+} __attribute__((__packed__));
+
+
+#define ACPI_RSDT_SIG "RSDT"
+
+struct acpi_rsdt {
+ struct acpi_dhdr header;
+ uint32_t entry[0];
+} __attribute__((__packed__));
+
+#define ACPI_XSDT_SIG "XSDT"
+
+struct acpi_xsdt {
+ struct acpi_dhdr header;
+ uint64_t entry[0];
+} __attribute__((__packed__));
+
+struct acpi_address {
+ uint8_t is_io;
+ uint8_t reg_width;
+ uint8_t reg_offset;
+ uint8_t reserved;
+ uint64_t addr64;
+} __attribute__((__packed__));
+
+/* APIC table signature. */
+#define ACPI_APIC_SIG "APIC"
+
+/* Types value for MADT entries: Local APIC, IOAPIC and IRQ Override. */
+enum ACPI_APIC_ENTRY_TYPE {
+ ACPI_APIC_ENTRY_LAPIC = 0,
+ ACPI_APIC_ENTRY_IOAPIC = 1,
+ ACPI_APIC_ENTRY_IRQ_OVERRIDE = 2,
+ ACPI_APIC_ENTRY_NONMASK_IRQ = 4
+};
+
+/*
+ * APIC descriptor header
+ * Define the type of the structure (Local APIC, I/O APIC or others).
+ * Type: Local APIC (0), I/O APIC (1).
+ */
+struct acpi_apic_dhdr {
+ uint8_t type;
+ uint8_t length;
+} __attribute__((__packed__));
+
+
+/*
+ * Multiple APIC Description Table (MADT)
+ *
+ * Describes the APIC structures which exist in the machine.
+ * Includes the common address where Local APIC is mapped in main memory.
+ *
+ * Entry field stores the descriptors of APIC structures.
+ */
+struct acpi_apic {
+ struct acpi_dhdr header; /* Header, which stores the descriptor for RDST's Entry field. */
+ uint32_t lapic_addr; /* Local Interrupt Controller Address. */
+ uint32_t flags;
+ struct acpi_apic_dhdr entry[0]; /* Interrupt Controller Structure */
+} __attribute__((__packed__));
+
+/*
+ * Processor Local APIC Structure
+ *
+ * Stores information about APIC ID, flags and ACPI Processor UID
+ */
+
+struct acpi_apic_lapic {
+ struct acpi_apic_dhdr header;
+ uint8_t processor_id; /* ACPI Processor UID */
+ uint8_t apic_id;
+ uint32_t flags;
+} __attribute__((__packed__));
+
+
+/*
+ * I/O APIC Structure
+ *
+ * Stores information about APIC ID, and I/O APIC tables
+ */
+
+struct acpi_apic_ioapic {
+ struct acpi_apic_dhdr header;
+ uint8_t apic_id;
+ uint8_t reserved;
+ uint32_t addr;
+ uint32_t gsi_base;
+} __attribute__((__packed__));
+
+/*
+ * IRQ Override structure
+ *
+ * Stores information about IRQ override, with busses and IRQ.
+ */
+
+struct acpi_apic_irq_override {
+ struct acpi_apic_dhdr header;
+ uint8_t bus;
+ uint8_t irq;
+ uint32_t gsi;
+ uint16_t flags;
+} __attribute__((__packed__));
+
+
+#define ACPI_HPET_SIG "HPET"
+
+/*
+ * HPET High Precision Event Timer structure
+ */
+struct acpi_hpet {
+ struct acpi_dhdr header;
+ uint32_t id;
+ struct acpi_address address;
+ uint8_t sequence;
+ uint16_t minimum_tick;
+ uint8_t flags;
+} __attribute__((__packed__));
+
+int acpi_apic_init(void);
+void acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n);
+
+extern unsigned lapic_addr;
+
+#endif /* __ACPI_H__ */
diff --git a/i386/i386at/autoconf.c b/i386/i386at/autoconf.c
new file mode 100644
index 0000000..5c69988
--- /dev/null
+++ b/i386/i386at/autoconf.c
@@ -0,0 +1,149 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990,1989 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.
+ */
+
+#include <kern/printf.h>
+#include <mach/std_types.h>
+#include <i386at/autoconf.h>
+#include <i386/irq.h>
+#include <i386/ipl.h>
+#ifdef APIC
+# include <i386/apic.h>
+#else
+# include <i386/pic.h>
+#endif
+#include <chips/busses.h>
+
+/* initialization typecasts */
+#define SPL_FIVE (vm_offset_t)SPL5
+#define SPL_SIX (vm_offset_t)SPL6
+#define SPL_TTY (vm_offset_t)SPLTTY
+
+
+#if NCOM > 0
+extern struct bus_driver comdriver;
+#include <i386at/com.h>
+#endif /* NCOM */
+
+#if NLPR > 0
+extern struct bus_driver lprdriver;
+#include <i386at/lpr.h>
+#endif /* NLPR */
+
+struct bus_ctlr bus_master_init[] = {
+
+/* driver name unit intr address len phys_address
+ adaptor alive flags spl pic */
+
+ {0}
+};
+
+
+struct bus_device bus_device_init[] = {
+
+/* driver name unit intr address am phys_address
+ adaptor alive ctlr slave flags *mi *next sysdep sysdep */
+
+#if NCOM > 0
+ {&comdriver, "com", 0, comintr, 0x3f8, 8, 0x3f8,
+ '?', 0, -1, -1, 0, 0, 0, SPL_TTY, 4},
+ {&comdriver, "com", 1, comintr, 0x2f8, 8, 0x2f8,
+ '?', 0, -1, -1, 0, 0, 0, SPL_TTY, 3},
+ {&comdriver, "com", 2, comintr, 0x3e8, 8, 0x3e8,
+ '?', 0, -1, -1, 0, 0, 0, SPL_TTY, 5},
+#endif /* NCOM > 0 */
+
+#ifdef MACH_LPR
+#if NLPR > 0
+ {&lprdriver, "lpr", 0, lprintr, 0x378, 3, 0x378,
+ '?', 0, -1, -1, 0, 0, 0, SPL_TTY, 7},
+ {&lprdriver, "lpr", 0, lprintr, 0x278, 3, 0x278,
+ '?', 0, -1, -1, 0, 0, 0, SPL_TTY, 7},
+ {&lprdriver, "lpr", 0, lprintr, 0x3bc, 3, 0x3bc,
+ '?', 0, -1, -1, 0, 0, 0, SPL_TTY, 7},
+#endif /* NLPR > 0 */
+#endif /* MACH_LPR */
+
+ {0}
+};
+
+/*
+ * probeio:
+ *
+ * Probe and subsequently attach devices out on the AT bus.
+ *
+ *
+ */
+void probeio(void)
+{
+ struct bus_device *device;
+ struct bus_ctlr *master;
+ int i = 0;
+
+ for (master = bus_master_init; master->driver; master++)
+ {
+ if (configure_bus_master(master->name, master->address,
+ master->phys_address, i, "atbus"))
+ i++;
+ }
+
+ for (device = bus_device_init; device->driver; device++)
+ {
+ /* ignore what we (should) have found already */
+ if (device->alive || device->ctlr >= 0)
+ continue;
+ if (configure_bus_device(device->name, device->address,
+ device->phys_address, i, "atbus"))
+ i++;
+ }
+
+#if MACH_TTD
+ /*
+ * Initialize Remote kernel debugger.
+ */
+ ttd_init();
+#endif /* MACH_TTD */
+}
+
+void take_dev_irq(
+ const struct bus_device *dev)
+{
+ int pic = (int)dev->sysdep1;
+
+ if (ivect[pic] == intnull) {
+ iunit[pic] = dev->unit;
+ ivect[pic] = dev->intr;
+ } else {
+ printf("The device below will clobber IRQ %d (%p).\n", pic, ivect[pic]);
+ printf("You have two devices at the same IRQ.\n");
+ printf("This won't work. Reconfigure your hardware and try again.\n");
+ printf("%s%d: port = %zx, spl = %zd, pic = %d.\n",
+ dev->name, dev->unit, dev->address,
+ dev->sysdep, dev->sysdep1);
+ while (1);
+ }
+
+ unmask_irq(pic);
+}
diff --git a/i386/i386at/autoconf.h b/i386/i386at/autoconf.h
new file mode 100644
index 0000000..81fc5da
--- /dev/null
+++ b/i386/i386at/autoconf.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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, 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, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+/*
+ * Device auto configuration.
+ *
+ */
+
+#ifndef _AUTOCONF_H_
+#define _AUTOCONF_H_
+
+#include <mach/std_types.h>
+#include <chips/busses.h>
+
+/*
+ * probeio:
+ *
+ * Probe and subsequently attach devices out on the AT bus.
+ *
+ *
+ */
+void probeio(void);
+
+void take_dev_irq(
+ const struct bus_device *dev);
+
+#endif /* _AUTOCONF_H_ */
diff --git a/i386/i386at/biosmem.c b/i386/i386at/biosmem.c
new file mode 100644
index 0000000..937c0e3
--- /dev/null
+++ b/i386/i386at/biosmem.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (c) 2010-2014 Richard Braun.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <inttypes.h>
+#include <i386/model_dep.h>
+#include <i386at/biosmem.h>
+#include <kern/assert.h>
+#include <kern/debug.h>
+#include <kern/macros.h>
+#include <kern/printf.h>
+#include <mach/vm_param.h>
+#include <mach/xen.h>
+#include <mach/machine/multiboot.h>
+#include <sys/types.h>
+#include <vm/vm_page.h>
+
+#define DEBUG 0
+
+#define __boot
+#define __bootdata
+#define __init
+
+#define boot_memmove memmove
+#define boot_panic(s) panic("%s", s)
+#define boot_strlen strlen
+
+#define BOOT_CGAMEM phystokv(0xb8000)
+#define BOOT_CGACHARS (80 * 25)
+#define BOOT_CGACOLOR 0x7
+
+#define BIOSMEM_MAX_BOOT_DATA 64
+
+/*
+ * Boot data descriptor.
+ *
+ * The start and end addresses must not be page-aligned, since there
+ * could be more than one range inside a single page.
+ */
+struct biosmem_boot_data {
+ phys_addr_t start;
+ phys_addr_t end;
+ boolean_t temporary;
+};
+
+/*
+ * Sorted array of boot data descriptors.
+ */
+static struct biosmem_boot_data biosmem_boot_data_array[BIOSMEM_MAX_BOOT_DATA]
+ __bootdata;
+static unsigned int biosmem_nr_boot_data __bootdata;
+
+/*
+ * Maximum number of entries in the BIOS memory map.
+ *
+ * Because of adjustments of overlapping ranges, the memory map can grow
+ * to twice this size.
+ */
+#define BIOSMEM_MAX_MAP_SIZE 128
+
+/*
+ * Memory range types.
+ */
+#define BIOSMEM_TYPE_AVAILABLE 1
+#define BIOSMEM_TYPE_RESERVED 2
+#define BIOSMEM_TYPE_ACPI 3
+#define BIOSMEM_TYPE_NVS 4
+#define BIOSMEM_TYPE_UNUSABLE 5
+#define BIOSMEM_TYPE_DISABLED 6
+
+/*
+ * Bitmask corresponding to memory ranges that require narrowing
+ * to page boundaries.
+ */
+#define BIOSMEM_MASK_NARROW (((1u << BIOSMEM_TYPE_AVAILABLE) | \
+ (1u << BIOSMEM_TYPE_NVS) | \
+ (1u << BIOSMEM_TYPE_DISABLED)))
+
+/*
+ * Helper macro to test if range type needs narrowing.
+ */
+#define BIOSMEM_NEEDS_NARROW(t) ((1u << t) & BIOSMEM_MASK_NARROW)
+
+/*
+ * Memory map entry.
+ */
+struct biosmem_map_entry {
+ uint64_t base_addr;
+ uint64_t length;
+ unsigned int type;
+};
+
+/*
+ * Memory map built from the information passed by the boot loader.
+ *
+ * If the boot loader didn't pass a valid memory map, a simple map is built
+ * based on the mem_lower and mem_upper multiboot fields.
+ */
+static struct biosmem_map_entry biosmem_map[BIOSMEM_MAX_MAP_SIZE * 2]
+ __bootdata;
+static unsigned int biosmem_map_size __bootdata;
+
+/*
+ * Contiguous block of physical memory.
+ */
+struct biosmem_segment {
+ phys_addr_t start;
+ phys_addr_t end;
+};
+
+/*
+ * Physical segment boundaries.
+ */
+static struct biosmem_segment biosmem_segments[VM_PAGE_MAX_SEGS] __bootdata;
+
+/*
+ * Boundaries of the simple bootstrap heap.
+ *
+ * This heap is located above BIOS memory.
+ */
+static phys_addr_t biosmem_heap_start __bootdata;
+static phys_addr_t biosmem_heap_bottom __bootdata;
+static phys_addr_t biosmem_heap_top __bootdata;
+static phys_addr_t biosmem_heap_end __bootdata;
+
+/*
+ * Boot allocation policy.
+ *
+ * Top-down allocations are normally preferred to avoid unnecessarily
+ * filling the DMA segment.
+ */
+static boolean_t biosmem_heap_topdown __bootdata;
+
+static char biosmem_panic_inval_boot_data[] __bootdata
+ = "biosmem: invalid boot data";
+static char biosmem_panic_too_many_boot_data[] __bootdata
+ = "biosmem: too many boot data ranges";
+static char biosmem_panic_too_big_msg[] __bootdata
+ = "biosmem: too many memory map entries";
+#ifndef MACH_HYP
+static char biosmem_panic_setup_msg[] __bootdata
+ = "biosmem: unable to set up the early memory allocator";
+#endif /* MACH_HYP */
+static char biosmem_panic_noseg_msg[] __bootdata
+ = "biosmem: unable to find any memory segment";
+static char biosmem_panic_inval_msg[] __bootdata
+ = "biosmem: attempt to allocate 0 page";
+static char biosmem_panic_nomem_msg[] __bootdata
+ = "biosmem: unable to allocate memory";
+
+void __boot
+biosmem_register_boot_data(phys_addr_t start, phys_addr_t end,
+ boolean_t temporary)
+{
+ unsigned int i;
+
+ if (start >= end) {
+ boot_panic(biosmem_panic_inval_boot_data);
+ }
+
+ if (biosmem_nr_boot_data == ARRAY_SIZE(biosmem_boot_data_array)) {
+ boot_panic(biosmem_panic_too_many_boot_data);
+ }
+
+ for (i = 0; i < biosmem_nr_boot_data; i++) {
+ /* Check if the new range overlaps */
+ if ((end > biosmem_boot_data_array[i].start)
+ && (start < biosmem_boot_data_array[i].end)) {
+
+ /*
+ * If it does, check whether it's part of another range.
+ * For example, this applies to debugging symbols directly
+ * taken from the kernel image.
+ */
+ if ((start >= biosmem_boot_data_array[i].start)
+ && (end <= biosmem_boot_data_array[i].end)) {
+
+ /*
+ * If it's completely included, make sure that a permanent
+ * range remains permanent.
+ *
+ * XXX This means that if one big range is first registered
+ * as temporary, and a smaller range inside of it is
+ * registered as permanent, the bigger range becomes
+ * permanent. It's not easy nor useful in practice to do
+ * better than that.
+ */
+ if (biosmem_boot_data_array[i].temporary != temporary) {
+ biosmem_boot_data_array[i].temporary = FALSE;
+ }
+
+ return;
+ }
+
+ boot_panic(biosmem_panic_inval_boot_data);
+ }
+
+ if (end <= biosmem_boot_data_array[i].start) {
+ break;
+ }
+ }
+
+ boot_memmove(&biosmem_boot_data_array[i + 1],
+ &biosmem_boot_data_array[i],
+ (biosmem_nr_boot_data - i) * sizeof(*biosmem_boot_data_array));
+
+ biosmem_boot_data_array[i].start = start;
+ biosmem_boot_data_array[i].end = end;
+ biosmem_boot_data_array[i].temporary = temporary;
+ biosmem_nr_boot_data++;
+}
+
+static void __init
+biosmem_unregister_boot_data(phys_addr_t start, phys_addr_t end)
+{
+ unsigned int i;
+
+ if (start >= end) {
+ panic("%s", biosmem_panic_inval_boot_data);
+ }
+
+ assert(biosmem_nr_boot_data != 0);
+
+ for (i = 0; biosmem_nr_boot_data; i++) {
+ if ((start == biosmem_boot_data_array[i].start)
+ && (end == biosmem_boot_data_array[i].end)) {
+ break;
+ }
+ }
+
+ if (i == biosmem_nr_boot_data) {
+ return;
+ }
+
+#if DEBUG
+ printf("biosmem: unregister boot data: %llx:%llx\n",
+ (unsigned long long)biosmem_boot_data_array[i].start,
+ (unsigned long long)biosmem_boot_data_array[i].end);
+#endif /* DEBUG */
+
+ biosmem_nr_boot_data--;
+
+ boot_memmove(&biosmem_boot_data_array[i],
+ &biosmem_boot_data_array[i + 1],
+ (biosmem_nr_boot_data - i) * sizeof(*biosmem_boot_data_array));
+}
+
+#ifndef MACH_HYP
+
+static void __boot
+biosmem_map_adjust_alignment(struct biosmem_map_entry *e)
+{
+ uint64_t end = e->base_addr + e->length;
+
+ if (BIOSMEM_NEEDS_NARROW(e->type)) {
+ e->base_addr = vm_page_round (e->base_addr);
+ e->length = vm_page_trunc (end) - e->base_addr;
+ }
+}
+
+static void __boot
+biosmem_map_build(const struct multiboot_raw_info *mbi)
+{
+ struct multiboot_raw_mmap_entry *mb_entry, *mb_end;
+ struct biosmem_map_entry *start, *entry, *end;
+ unsigned long addr;
+
+ addr = phystokv(mbi->mmap_addr);
+ mb_entry = (struct multiboot_raw_mmap_entry *)addr;
+ mb_end = (struct multiboot_raw_mmap_entry *)(addr + mbi->mmap_length);
+ start = biosmem_map;
+ entry = start;
+ end = entry + BIOSMEM_MAX_MAP_SIZE;
+
+ while ((mb_entry < mb_end) && (entry < end)) {
+ entry->base_addr = mb_entry->base_addr;
+ entry->length = mb_entry->length;
+ entry->type = mb_entry->type;
+
+ mb_entry = (void *)mb_entry + sizeof(mb_entry->size) + mb_entry->size;
+
+ biosmem_map_adjust_alignment(entry);
+ entry++;
+ }
+
+ biosmem_map_size = entry - start;
+}
+
+static void __boot
+biosmem_map_build_simple(const struct multiboot_raw_info *mbi)
+{
+ struct biosmem_map_entry *entry;
+
+ entry = biosmem_map;
+ entry->base_addr = 0;
+ entry->length = mbi->mem_lower << 10;
+ entry->type = BIOSMEM_TYPE_AVAILABLE;
+ biosmem_map_adjust_alignment(entry);
+
+ entry++;
+ entry->base_addr = BIOSMEM_END;
+ entry->length = mbi->mem_upper << 10;
+ entry->type = BIOSMEM_TYPE_AVAILABLE;
+ biosmem_map_adjust_alignment(entry);
+
+ biosmem_map_size = 2;
+}
+
+#endif /* MACH_HYP */
+
+static int __boot
+biosmem_map_entry_is_invalid(const struct biosmem_map_entry *entry)
+{
+ return (entry->base_addr + entry->length) <= entry->base_addr;
+}
+
+static void __boot
+biosmem_map_filter(void)
+{
+ struct biosmem_map_entry *entry;
+ unsigned int i;
+
+ i = 0;
+
+ while (i < biosmem_map_size) {
+ entry = &biosmem_map[i];
+
+ if (biosmem_map_entry_is_invalid(entry)) {
+ biosmem_map_size--;
+ boot_memmove(entry, entry + 1,
+ (biosmem_map_size - i) * sizeof(*entry));
+ continue;
+ }
+
+ i++;
+ }
+}
+
+static void __boot
+biosmem_map_sort(void)
+{
+ struct biosmem_map_entry tmp;
+ unsigned int i, j;
+
+ /*
+ * Simple insertion sort.
+ */
+ for (i = 1; i < biosmem_map_size; i++) {
+ tmp = biosmem_map[i];
+
+ for (j = i - 1; j < i; j--) {
+ if (biosmem_map[j].base_addr < tmp.base_addr)
+ break;
+
+ biosmem_map[j + 1] = biosmem_map[j];
+ }
+
+ biosmem_map[j + 1] = tmp;
+ }
+}
+
+static void __boot
+biosmem_map_adjust(void)
+{
+ struct biosmem_map_entry tmp, *a, *b, *first, *second;
+ uint64_t a_end, b_end, last_end;
+ unsigned int i, j, last_type;
+
+ biosmem_map_filter();
+
+ /*
+ * Resolve overlapping areas, giving priority to most restrictive
+ * (i.e. numerically higher) types.
+ */
+ for (i = 0; i < biosmem_map_size; i++) {
+ a = &biosmem_map[i];
+ a_end = a->base_addr + a->length;
+
+ j = i + 1;
+
+ while (j < biosmem_map_size) {
+ b = &biosmem_map[j];
+ b_end = b->base_addr + b->length;
+
+ if ((a->base_addr >= b_end) || (a_end <= b->base_addr)) {
+ j++;
+ continue;
+ }
+
+ if (a->base_addr < b->base_addr) {
+ first = a;
+ second = b;
+ } else {
+ first = b;
+ second = a;
+ }
+
+ if (a_end > b_end) {
+ last_end = a_end;
+ last_type = a->type;
+ } else {
+ last_end = b_end;
+ last_type = b->type;
+ }
+
+ tmp.base_addr = second->base_addr;
+ tmp.length = MIN(a_end, b_end) - tmp.base_addr;
+ tmp.type = MAX(a->type, b->type);
+ first->length = tmp.base_addr - first->base_addr;
+ second->base_addr += tmp.length;
+ second->length = last_end - second->base_addr;
+ second->type = last_type;
+
+ /*
+ * Filter out invalid entries.
+ */
+ if (biosmem_map_entry_is_invalid(a)
+ && biosmem_map_entry_is_invalid(b)) {
+ *a = tmp;
+ biosmem_map_size--;
+ memmove(b, b + 1, (biosmem_map_size - j) * sizeof(*b));
+ continue;
+ } else if (biosmem_map_entry_is_invalid(a)) {
+ *a = tmp;
+ j++;
+ continue;
+ } else if (biosmem_map_entry_is_invalid(b)) {
+ *b = tmp;
+ j++;
+ continue;
+ }
+
+ if (tmp.type == a->type)
+ first = a;
+ else if (tmp.type == b->type)
+ first = b;
+ else {
+
+ /*
+ * If the overlapping area can't be merged with one of its
+ * neighbors, it must be added as a new entry.
+ */
+
+ if (biosmem_map_size >= ARRAY_SIZE(biosmem_map))
+ boot_panic(biosmem_panic_too_big_msg);
+
+ biosmem_map[biosmem_map_size] = tmp;
+ biosmem_map_size++;
+ j++;
+ continue;
+ }
+
+ if (first->base_addr > tmp.base_addr)
+ first->base_addr = tmp.base_addr;
+
+ first->length += tmp.length;
+ j++;
+ }
+ }
+
+ biosmem_map_sort();
+}
+
+/*
+ * Find addresses of physical memory within a given range.
+ *
+ * This function considers the memory map with the [*phys_start, *phys_end]
+ * range on entry, and returns the lowest address of physical memory
+ * in *phys_start, and the highest address of unusable memory immediately
+ * following physical memory in *phys_end.
+ *
+ * These addresses are normally used to establish the range of a segment.
+ */
+static int __boot
+biosmem_map_find_avail(phys_addr_t *phys_start, phys_addr_t *phys_end)
+{
+ const struct biosmem_map_entry *entry, *map_end;
+ phys_addr_t seg_start, seg_end;
+ uint64_t start, end;
+
+ seg_start = (phys_addr_t)-1;
+ seg_end = (phys_addr_t)-1;
+ map_end = biosmem_map + biosmem_map_size;
+
+ for (entry = biosmem_map; entry < map_end; entry++) {
+ if (entry->type != BIOSMEM_TYPE_AVAILABLE)
+ continue;
+
+ start = vm_page_round(entry->base_addr);
+
+ if (start >= *phys_end)
+ break;
+
+ end = vm_page_trunc(entry->base_addr + entry->length);
+
+ if ((start < end) && (start < *phys_end) && (end > *phys_start)) {
+ if (seg_start == (phys_addr_t)-1)
+ seg_start = start;
+
+ seg_end = end;
+ }
+ }
+
+ if ((seg_start == (phys_addr_t)-1) || (seg_end == (phys_addr_t)-1))
+ return -1;
+
+ if (seg_start > *phys_start)
+ *phys_start = seg_start;
+
+ if (seg_end < *phys_end)
+ *phys_end = seg_end;
+
+ return 0;
+}
+
+static void __boot
+biosmem_set_segment(unsigned int seg_index, phys_addr_t start, phys_addr_t end)
+{
+ biosmem_segments[seg_index].start = start;
+ biosmem_segments[seg_index].end = end;
+}
+
+static phys_addr_t __boot
+biosmem_segment_end(unsigned int seg_index)
+{
+ return biosmem_segments[seg_index].end;
+}
+
+static phys_addr_t __boot
+biosmem_segment_size(unsigned int seg_index)
+{
+ return biosmem_segments[seg_index].end - biosmem_segments[seg_index].start;
+}
+
+static int __boot
+biosmem_find_avail_clip(phys_addr_t *avail_start, phys_addr_t *avail_end,
+ phys_addr_t data_start, phys_addr_t data_end)
+{
+ phys_addr_t orig_end;
+
+ assert(data_start < data_end);
+
+ orig_end = data_end;
+ data_start = vm_page_trunc(data_start);
+ data_end = vm_page_round(data_end);
+
+ if (data_end < orig_end) {
+ boot_panic(biosmem_panic_inval_boot_data);
+ }
+
+ if ((data_end <= *avail_start) || (data_start >= *avail_end)) {
+ return 0;
+ }
+
+ if (data_start > *avail_start) {
+ *avail_end = data_start;
+ } else {
+ if (data_end >= *avail_end) {
+ return -1;
+ }
+
+ *avail_start = data_end;
+ }
+
+ return 0;
+}
+
+/*
+ * Find available memory in the given range.
+ *
+ * The search starts at the given start address, up to the given end address.
+ * If a range is found, it is stored through the avail_startp and avail_endp
+ * pointers.
+ *
+ * The range boundaries are page-aligned on return.
+ */
+static int __boot
+biosmem_find_avail(phys_addr_t start, phys_addr_t end,
+ phys_addr_t *avail_start, phys_addr_t *avail_end)
+{
+ phys_addr_t orig_start;
+ unsigned int i;
+ int error;
+
+ assert(start <= end);
+
+ orig_start = start;
+ start = vm_page_round(start);
+ end = vm_page_trunc(end);
+
+ if ((start < orig_start) || (start >= end)) {
+ return -1;
+ }
+
+ *avail_start = start;
+ *avail_end = end;
+
+ for (i = 0; i < biosmem_nr_boot_data; i++) {
+ error = biosmem_find_avail_clip(avail_start, avail_end,
+ biosmem_boot_data_array[i].start,
+ biosmem_boot_data_array[i].end);
+
+ if (error) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#ifndef MACH_HYP
+
+static void __boot
+biosmem_setup_allocator(const struct multiboot_raw_info *mbi)
+{
+ phys_addr_t heap_start, heap_end, max_heap_start, max_heap_end;
+ phys_addr_t start, end;
+ int error;
+
+ /*
+ * Find some memory for the heap. Look for the largest unused area in
+ * upper memory, carefully avoiding all boot data.
+ */
+ end = vm_page_trunc((mbi->mem_upper + 1024) << 10);
+
+ if (end > VM_PAGE_DIRECTMAP_LIMIT)
+ end = VM_PAGE_DIRECTMAP_LIMIT;
+
+ max_heap_start = 0;
+ max_heap_end = 0;
+ start = BIOSMEM_END;
+
+ for (;;) {
+ error = biosmem_find_avail(start, end, &heap_start, &heap_end);
+
+ if (error) {
+ break;
+ }
+
+ if ((heap_end - heap_start) > (max_heap_end - max_heap_start)) {
+ max_heap_start = heap_start;
+ max_heap_end = heap_end;
+ }
+
+ start = heap_end;
+ }
+
+ if (max_heap_start >= max_heap_end)
+ boot_panic(biosmem_panic_setup_msg);
+
+ biosmem_heap_start = max_heap_start;
+ biosmem_heap_end = max_heap_end;
+ biosmem_heap_bottom = biosmem_heap_start;
+ biosmem_heap_top = biosmem_heap_end;
+ biosmem_heap_topdown = TRUE;
+
+ /* Prevent biosmem_free_usable() from releasing the heap */
+ biosmem_register_boot_data(biosmem_heap_start, biosmem_heap_end, FALSE);
+}
+
+#endif /* MACH_HYP */
+
+static void __boot
+biosmem_bootstrap_common(void)
+{
+ phys_addr_t phys_start, phys_end;
+ int error;
+
+ biosmem_map_adjust();
+
+ phys_start = BIOSMEM_BASE;
+ phys_end = VM_PAGE_DMA_LIMIT;
+ error = biosmem_map_find_avail(&phys_start, &phys_end);
+
+ if (error)
+ boot_panic(biosmem_panic_noseg_msg);
+
+#if !defined(MACH_HYP) && NCPUS > 1
+ /*
+ * Grab an early page for AP boot code which needs to be below 1MB.
+ */
+ assert (phys_start < 0x100000);
+ apboot_addr = phys_start;
+ phys_start += PAGE_SIZE;
+#endif
+
+ biosmem_set_segment(VM_PAGE_SEG_DMA, phys_start, phys_end);
+
+ phys_start = VM_PAGE_DMA_LIMIT;
+
+#ifdef VM_PAGE_DMA32_LIMIT
+#if VM_PAGE_DMA32_LIMIT < VM_PAGE_DIRECTMAP_LIMIT
+ phys_end = VM_PAGE_DMA32_LIMIT;
+ error = biosmem_map_find_avail(&phys_start, &phys_end);
+
+ if (error)
+ return;
+
+ biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
+
+ phys_start = VM_PAGE_DMA32_LIMIT;
+#endif
+#endif /* VM_PAGE_DMA32_LIMIT */
+
+ phys_end = VM_PAGE_DIRECTMAP_LIMIT;
+ error = biosmem_map_find_avail(&phys_start, &phys_end);
+
+ if (error)
+ return;
+
+ biosmem_set_segment(VM_PAGE_SEG_DIRECTMAP, phys_start, phys_end);
+
+ phys_start = VM_PAGE_DIRECTMAP_LIMIT;
+
+#ifdef VM_PAGE_DMA32_LIMIT
+#if VM_PAGE_DMA32_LIMIT > VM_PAGE_DIRECTMAP_LIMIT
+ phys_end = VM_PAGE_DMA32_LIMIT;
+ error = biosmem_map_find_avail(&phys_start, &phys_end);
+
+ if (error)
+ return;
+
+ biosmem_set_segment(VM_PAGE_SEG_DMA32, phys_start, phys_end);
+
+ phys_start = VM_PAGE_DMA32_LIMIT;
+#endif
+#endif /* VM_PAGE_DMA32_LIMIT */
+
+ phys_end = VM_PAGE_HIGHMEM_LIMIT;
+ error = biosmem_map_find_avail(&phys_start, &phys_end);
+
+ if (error)
+ return;
+
+ biosmem_set_segment(VM_PAGE_SEG_HIGHMEM, phys_start, phys_end);
+}
+
+#ifdef MACH_HYP
+
+void
+biosmem_xen_bootstrap(void)
+{
+ struct biosmem_map_entry *entry;
+
+ entry = biosmem_map;
+ entry->base_addr = 0;
+ entry->length = boot_info.nr_pages << PAGE_SHIFT;
+ entry->type = BIOSMEM_TYPE_AVAILABLE;
+
+ biosmem_map_size = 1;
+
+ biosmem_bootstrap_common();
+
+ biosmem_heap_start = _kvtophys(boot_info.pt_base)
+ + (boot_info.nr_pt_frames + 3) * 0x1000;
+ biosmem_heap_end = boot_info.nr_pages << PAGE_SHIFT;
+
+#ifndef __LP64__
+ if (biosmem_heap_end > VM_PAGE_DIRECTMAP_LIMIT)
+ biosmem_heap_end = VM_PAGE_DIRECTMAP_LIMIT;
+#endif /* __LP64__ */
+
+ biosmem_heap_bottom = biosmem_heap_start;
+ biosmem_heap_top = biosmem_heap_end;
+
+ /*
+ * XXX Allocation on Xen are initially bottom-up :
+ * At the "start of day", only 512k are available after the boot
+ * data. The pmap module then creates a 4g mapping so all physical
+ * memory is available, but it uses this allocator to do so.
+ * Therefore, it must return pages from this small 512k regions
+ * first.
+ */
+ biosmem_heap_topdown = FALSE;
+
+ /*
+ * Prevent biosmem_free_usable() from releasing the Xen boot information
+ * and the heap.
+ */
+ biosmem_register_boot_data(0, biosmem_heap_end, FALSE);
+}
+
+#else /* MACH_HYP */
+
+void __boot
+biosmem_bootstrap(const struct multiboot_raw_info *mbi)
+{
+ if (mbi->flags & MULTIBOOT_LOADER_MMAP)
+ biosmem_map_build(mbi);
+ else
+ biosmem_map_build_simple(mbi);
+
+ biosmem_bootstrap_common();
+ biosmem_setup_allocator(mbi);
+}
+
+#endif /* MACH_HYP */
+
+unsigned long __boot
+biosmem_bootalloc(unsigned int nr_pages)
+{
+ unsigned long addr, size;
+
+ size = vm_page_ptoa(nr_pages);
+
+ if (size == 0)
+ boot_panic(biosmem_panic_inval_msg);
+
+ if (biosmem_heap_topdown) {
+ addr = biosmem_heap_top - size;
+
+ if ((addr < biosmem_heap_start) || (addr > biosmem_heap_top)) {
+ boot_panic(biosmem_panic_nomem_msg);
+ }
+
+ biosmem_heap_top = addr;
+ } else {
+ unsigned long end;
+
+ addr = biosmem_heap_bottom;
+ end = addr + size;
+
+ if ((end > biosmem_heap_end) || (end < biosmem_heap_bottom)) {
+ boot_panic(biosmem_panic_nomem_msg);
+ }
+
+ biosmem_heap_bottom = end;
+ }
+
+ return addr;
+}
+
+phys_addr_t __boot
+biosmem_directmap_end(void)
+{
+ if (biosmem_segment_size(VM_PAGE_SEG_DIRECTMAP) != 0)
+ return biosmem_segment_end(VM_PAGE_SEG_DIRECTMAP);
+#if defined(VM_PAGE_DMA32_LIMIT) && (VM_PAGE_DMA32_LIMIT < VM_PAGE_DIRECTMAP_LIMIT)
+ if (biosmem_segment_size(VM_PAGE_SEG_DMA32) != 0)
+ return biosmem_segment_end(VM_PAGE_SEG_DMA32);
+#endif
+ return biosmem_segment_end(VM_PAGE_SEG_DMA);
+}
+
+static const char * __init
+biosmem_type_desc(unsigned int type)
+{
+ switch (type) {
+ case BIOSMEM_TYPE_AVAILABLE:
+ return "available";
+ case BIOSMEM_TYPE_RESERVED:
+ return "reserved";
+ case BIOSMEM_TYPE_ACPI:
+ return "ACPI";
+ case BIOSMEM_TYPE_NVS:
+ return "ACPI NVS";
+ case BIOSMEM_TYPE_UNUSABLE:
+ return "unusable";
+ default:
+ return "unknown (reserved)";
+ }
+}
+
+static void __init
+biosmem_map_show(void)
+{
+ const struct biosmem_map_entry *entry, *end;
+
+ printf("biosmem: physical memory map:\n");
+
+ for (entry = biosmem_map, end = entry + biosmem_map_size;
+ entry < end;
+ entry++)
+ printf("biosmem: %018"PRIx64":%018"PRIx64", %s\n", entry->base_addr,
+ entry->base_addr + entry->length,
+ biosmem_type_desc(entry->type));
+
+#if DEBUG
+ printf("biosmem: heap: %llx:%llx\n",
+ (unsigned long long)biosmem_heap_start,
+ (unsigned long long)biosmem_heap_end);
+#endif
+}
+
+static void __init
+biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end)
+{
+ phys_addr_t phys_start, phys_end, avail_start, avail_end;
+ unsigned int seg_index;
+
+ phys_start = seg->start;
+ phys_end = seg->end;
+ seg_index = seg - biosmem_segments;
+
+ if (phys_end > max_phys_end) {
+ if (max_phys_end <= phys_start) {
+ printf("biosmem: warning: segment %s physically unreachable, "
+ "not loaded\n", vm_page_seg_name(seg_index));
+ return;
+ }
+
+ printf("biosmem: warning: segment %s truncated to %#"PRIx64"\n",
+ vm_page_seg_name(seg_index), max_phys_end);
+ phys_end = max_phys_end;
+ }
+
+ vm_page_load(seg_index, phys_start, phys_end);
+
+ /*
+ * Clip the remaining available heap to fit it into the loaded
+ * segment if possible.
+ */
+
+ if ((biosmem_heap_top > phys_start) && (biosmem_heap_bottom < phys_end)) {
+ if (biosmem_heap_bottom >= phys_start) {
+ avail_start = biosmem_heap_bottom;
+ } else {
+ avail_start = phys_start;
+ }
+
+ if (biosmem_heap_top <= phys_end) {
+ avail_end = biosmem_heap_top;
+ } else {
+ avail_end = phys_end;
+ }
+
+ vm_page_load_heap(seg_index, avail_start, avail_end);
+ }
+}
+
+void __init
+biosmem_setup(void)
+{
+ struct biosmem_segment *seg;
+ unsigned int i;
+
+ biosmem_map_show();
+
+ for (i = 0; i < ARRAY_SIZE(biosmem_segments); i++) {
+ if (biosmem_segment_size(i) == 0)
+ break;
+
+ seg = &biosmem_segments[i];
+ biosmem_load_segment(seg, VM_PAGE_HIGHMEM_LIMIT);
+ }
+}
+
+static void __init
+biosmem_unregister_temporary_boot_data(void)
+{
+ struct biosmem_boot_data *data;
+ unsigned int i;
+
+ for (i = 0; i < biosmem_nr_boot_data; i++) {
+ data = &biosmem_boot_data_array[i];
+
+ if (!data->temporary) {
+ continue;
+ }
+
+ biosmem_unregister_boot_data(data->start, data->end);
+ i = (unsigned int)-1;
+ }
+}
+
+static void __init
+biosmem_free_usable_range(phys_addr_t start, phys_addr_t end)
+{
+ struct vm_page *page;
+
+#if DEBUG
+ printf("biosmem: release to vm_page: %llx:%llx (%lluk)\n",
+ (unsigned long long)start, (unsigned long long)end,
+ (unsigned long long)((end - start) >> 10));
+#endif
+
+ while (start < end) {
+ page = vm_page_lookup_pa(start);
+ assert(page != NULL);
+ vm_page_manage(page);
+ start += PAGE_SIZE;
+ }
+}
+
+static void __init
+biosmem_free_usable_entry(phys_addr_t start, phys_addr_t end)
+{
+ phys_addr_t avail_start, avail_end;
+ int error;
+
+ for (;;) {
+ error = biosmem_find_avail(start, end, &avail_start, &avail_end);
+
+ if (error) {
+ break;
+ }
+
+ biosmem_free_usable_range(avail_start, avail_end);
+ start = avail_end;
+ }
+}
+
+void __init
+biosmem_free_usable(void)
+{
+ struct biosmem_map_entry *entry;
+ uint64_t start, end;
+ unsigned int i;
+
+ biosmem_unregister_temporary_boot_data();
+
+ for (i = 0; i < biosmem_map_size; i++) {
+ entry = &biosmem_map[i];
+
+ if (entry->type != BIOSMEM_TYPE_AVAILABLE)
+ continue;
+
+ start = vm_page_round(entry->base_addr);
+
+ if (start >= VM_PAGE_HIGHMEM_LIMIT)
+ break;
+
+ end = vm_page_trunc(entry->base_addr + entry->length);
+
+ if (end > VM_PAGE_HIGHMEM_LIMIT) {
+ end = VM_PAGE_HIGHMEM_LIMIT;
+ }
+
+ if (start < BIOSMEM_BASE)
+ start = BIOSMEM_BASE;
+
+ if (start >= end) {
+ continue;
+ }
+
+ biosmem_free_usable_entry(start, end);
+ }
+}
+
+boolean_t
+biosmem_addr_available(phys_addr_t addr)
+{
+ struct biosmem_map_entry *entry;
+ unsigned i;
+
+ if (addr < BIOSMEM_BASE)
+ return FALSE;
+
+ for (i = 0; i < biosmem_map_size; i++) {
+ entry = &biosmem_map[i];
+
+ if (addr >= entry->base_addr && addr < entry->base_addr + entry->length)
+ return entry->type == BIOSMEM_TYPE_AVAILABLE;
+ }
+ return FALSE;
+}
diff --git a/i386/i386at/biosmem.h b/i386/i386at/biosmem.h
new file mode 100644
index 0000000..76ab23a
--- /dev/null
+++ b/i386/i386at/biosmem.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2010-2014 Richard Braun.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _X86_BIOSMEM_H
+#define _X86_BIOSMEM_H
+
+#include <mach/machine/vm_types.h>
+#include <mach/machine/multiboot.h>
+
+/*
+ * Address where the address of the Extended BIOS Data Area segment can be
+ * found.
+ */
+#define BIOSMEM_EBDA_PTR 0x40e
+
+/*
+ * Significant low memory addresses.
+ *
+ * The first 64 KiB are reserved for various reasons (e.g. to preserve BIOS
+ * data and to work around data corruption on some hardware).
+ */
+#define BIOSMEM_BASE 0x010000
+#define BIOSMEM_BASE_END 0x0a0000
+#define BIOSMEM_EXT_ROM 0x0e0000
+#define BIOSMEM_ROM 0x0f0000
+#define BIOSMEM_END 0x100000
+
+/*
+ * Report reserved addresses to the biosmem module.
+ *
+ * Once all boot data have been registered, the user can set up the
+ * early page allocator.
+ *
+ * If the range is marked temporary, it will be unregistered when
+ * biosmem_free_usable() is called, so that pages that used to store
+ * these boot data may be released to the VM system.
+ */
+void biosmem_register_boot_data(phys_addr_t start, phys_addr_t end,
+ boolean_t temporary);
+
+/*
+ * Initialize the early page allocator.
+ *
+ * This function uses the memory map provided by the boot loader along
+ * with the registered boot data addresses to set up a heap of free pages
+ * of physical memory.
+ *
+ * Note that on Xen, this function registers all the Xen boot information
+ * as boot data itself.
+ */
+#ifdef MACH_HYP
+void biosmem_xen_bootstrap(void);
+#else /* MACH_HYP */
+void biosmem_bootstrap(const struct multiboot_raw_info *mbi);
+#endif /* MACH_HYP */
+
+/*
+ * Allocate contiguous physical pages during bootstrap.
+ *
+ * The pages returned are guaranteed to be part of the direct physical
+ * mapping when paging is enabled.
+ *
+ * This function should only be used to allocate initial page table pages.
+ * Those pages are later loaded into the VM system (as reserved pages)
+ * which means they can be freed like other regular pages. Users should
+ * fix up the type of those pages once the VM system is initialized.
+ */
+unsigned long biosmem_bootalloc(unsigned int nr_pages);
+
+/*
+ * Return the limit of physical memory that can be directly mapped.
+ */
+phys_addr_t biosmem_directmap_end(void);
+
+/*
+ * Set up physical memory based on the information obtained during bootstrap
+ * and load it in the VM system.
+ */
+void biosmem_setup(void);
+
+/*
+ * Free all usable memory.
+ *
+ * This function releases all pages that aren't used by boot data and have
+ * not already been loaded into the VM system.
+ */
+void biosmem_free_usable(void);
+
+/*
+ * Tell whether this address is marked as available in the biosmem and thus used
+ * for usable memory.
+ */
+boolean_t biosmem_addr_available(phys_addr_t addr);
+
+#endif /* _X86_BIOSMEM_H */
diff --git a/i386/i386at/boothdr.S b/i386/i386at/boothdr.S
new file mode 100644
index 0000000..daaf57d
--- /dev/null
+++ b/i386/i386at/boothdr.S
@@ -0,0 +1,179 @@
+
+#include <mach/machine/asm.h>
+#include <i386/apic.h>
+#include <i386/seg.h>
+#include <i386/i386asm.h>
+
+ /*
+ * This section will be put first into .text. See also i386/ldscript.
+ */
+ .section .text.start,"ax"
+
+ /* We should never be entered this way. */
+ .globl start,_start
+start:
+_start:
+ jmp boot_entry
+
+ /* MultiBoot header - see multiboot.h. */
+#define MULTIBOOT_MAGIC 0x1BADB002
+#ifdef __ELF__
+#define MULTIBOOT_FLAGS 0x00000003
+#else /* __ELF__ */
+#define MULTIBOOT_FLAGS 0x00010003
+#endif /* __ELF__ */
+ P2ALIGN(2)
+boot_hdr:
+ .long MULTIBOOT_MAGIC
+ .long MULTIBOOT_FLAGS
+ /*
+ * The next item here is the checksum.
+ * XX this works OK until we need at least the 30th bit.
+ */
+ .long - (MULTIBOOT_MAGIC+MULTIBOOT_FLAGS)
+#ifndef __ELF__ /* a.out kludge */
+ .long boot_hdr /* header_addr */
+ .long _start /* load_addr */
+ .long _edata /* load_end_addr */
+ .long _end /* bss_end_addr */
+ .long boot_entry /* entry */
+#endif /* __ELF__ */
+
+boot_entry:
+ movl $percpu_array - KERNELBASE, %eax
+ movw %ax, boot_percpu_low - KERNELBASE
+ shr $16, %eax
+ movb %al, boot_percpu_med - KERNELBASE
+ shr $8, %ax
+ movb %al, boot_percpu_high - KERNELBASE
+
+ /* use segmentation to offset ourself. */
+ lgdt boot_gdt_descr - KERNELBASE
+ ljmp $0x8,$0f
+0:
+ movw $0x0,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%fs
+ movw %ax,%gs
+ movw $0x10,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%ss
+ movw $0x68,%ax
+ movw %ax,%gs
+
+ /* Switch to our own interrupt stack. */
+ movl $solid_intstack+INTSTACK_SIZE-4, %esp
+ andl $0xfffffff0,%esp
+
+ /* Enable local apic in xAPIC mode */
+ xorl %eax, %eax
+ xorl %edx, %edx
+ movl $APIC_MSR, %ecx
+ rdmsr
+ orl $APIC_MSR_ENABLE, %eax
+ orl $APIC_MSR_BSP, %eax
+ andl $(~APIC_MSR_X2APIC), %eax
+ movl $APIC_MSR, %ecx
+ wrmsr
+
+ /* Reset EFLAGS to a known state. */
+ pushl $0
+ popf
+
+ /* Clear uninitialized data. */
+ lea _edata,%edi
+ lea _end,%ecx
+ subl %edi,%ecx
+ xorl %eax,%eax
+ rep
+ stosb
+
+ /* Push the boot_info pointer to be the second argument. */
+ pushl %ebx
+
+ /* Fix ifunc entries */
+ movl $__rel_iplt_start,%esi
+ movl $__rel_iplt_end,%edi
+iplt_cont:
+ cmpl %edi,%esi
+ jae iplt_done
+ movl (%esi),%ebx /* r_offset */
+ movb 4(%esi),%al /* info */
+ cmpb $42,%al /* IRELATIVE */
+ jnz iplt_next
+ call *(%ebx) /* call ifunc */
+ movl %eax,(%ebx) /* fixed address */
+iplt_next:
+ addl $8,%esi
+ jmp iplt_cont
+iplt_done:
+
+ /* Jump into C code. */
+ call EXT(c_boot_entry)
+
+.align 16
+ .word 0
+boot_gdt_descr:
+ .word 14*8-1
+ .long boot_gdt - KERNELBASE
+.align 16
+boot_gdt:
+ /* 0 */
+ .quad 0
+
+ /* boot CS = 0x08 */
+ .word 0xffff
+ .word (-KERNELBASE) & 0xffff
+ .byte ((-KERNELBASE) >> 16) & 0xff
+ .byte ACC_PL_K | ACC_CODE_R | ACC_P
+ .byte ((SZ_32 | SZ_G) << 4) | 0xf
+ .byte ((-KERNELBASE) >> 24) & 0xff
+
+ /* boot DS = 0x10 */
+ .word 0xffff
+ .word (-KERNELBASE) & 0xffff
+ .byte ((-KERNELBASE) >> 16) & 0xff
+ .byte ACC_PL_K | ACC_DATA_W | ACC_P
+ .byte ((SZ_32 | SZ_G) << 4) | 0xf
+ .byte ((-KERNELBASE) >> 24) & 0xff
+
+ /* 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
+boot_percpu_low:
+ .word 0
+boot_percpu_med:
+ .byte 0
+ .byte ACC_PL_K | ACC_DATA_W | ACC_P
+ .byte ((SZ_32 | SZ_G) << 4) | 0xf
+boot_percpu_high:
+ .byte 0
diff --git a/i386/i386at/com.c b/i386/i386at/com.c
new file mode 100644
index 0000000..bfe353c
--- /dev/null
+++ b/i386/i386at/com.c
@@ -0,0 +1,900 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1994,1993,1991,1990 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.
+ */
+
+#if NCOM > 0
+
+#include <string.h>
+#include <util/atoi.h>
+
+#include <mach/std_types.h>
+#include <sys/types.h>
+#include <kern/printf.h>
+#include <kern/mach_clock.h>
+#include <device/conf.h>
+#include <device/device_types.h>
+#include <device/tty.h>
+#include <device/io_req.h>
+
+#include <i386/ipl.h>
+#include <i386/pio.h>
+#include <i386/machspl.h>
+#include <chips/busses.h>
+#include <i386at/autoconf.h>
+#include <i386at/com.h>
+#include <i386at/comreg.h>
+
+#include <device/cons.h>
+
+static void comparam(int);
+
+static vm_offset_t com_std[NCOM] = { 0 };
+struct bus_device *cominfo[NCOM];
+struct bus_driver comdriver = {
+ comprobe, 0, comattach, 0, com_std, "com", cominfo, 0, 0, 0};
+
+struct tty com_tty[NCOM];
+int commodem[NCOM];
+int comcarrier[NCOM] = {0, 0,};
+boolean_t comfifo[NCOM];
+boolean_t comtimer_active;
+int comtimer_state[NCOM];
+
+#define RCBAUD B115200
+static int rcline = -1;
+static struct bus_device *comcndev;
+
+/* XX */
+extern char *kernel_cmdline;
+
+#define ISPEED B115200
+#define IFLAGS (EVENP|ODDP|ECHO|CRMOD|XTABS|LITOUT)
+
+u_short divisorreg[] = {
+ 0, 2304, 1536, 1047, /* 0, 50, 75, 110*/
+ 857, 768, 576, 384, 192, /* 134.5, 150, 200, 300, 600*/
+ 96, 64, 48, /* 1200, 1800, 2000, 2400 */
+ 24, 12, /* 3600, 4800, 7200, 9600 */
+ 6, 3, 2, 1}; /* 19200, 38400, 56000,115200 */
+
+
+/*
+ *
+ * Probes are called during kernel boot: return 1 to mean that
+ * the relevant device is present today.
+ *
+ */
+static int
+comprobe_general(struct bus_device *dev, int noisy)
+{
+ u_short addr = dev->address;
+ int unit = dev->unit;
+ int oldctl, oldmsb;
+ char *type = "8250";
+ int i;
+
+ if ((unit < 0) || (unit >= NCOM)) {
+ printf("com %d out of range\n", unit);
+ return(0);
+ }
+ oldctl = inb(LINE_CTL(addr)); /* Save old value of LINE_CTL */
+ oldmsb = inb(BAUD_MSB(addr)); /* Save old value of BAUD_MSB */
+ outb(LINE_CTL(addr), 0); /* Select INTR_ENAB */
+ outb(BAUD_MSB(addr), 0);
+ if (inb(BAUD_MSB(addr)) != 0)
+ {
+ outb(LINE_CTL(addr), oldctl);
+ outb(BAUD_MSB(addr), oldmsb);
+ return 0;
+ }
+ outb(LINE_CTL(addr), iDLAB); /* Select BAUD_MSB */
+ outb(BAUD_MSB(addr), 255);
+ if (inb(BAUD_MSB(addr)) != 255)
+ {
+ outb(LINE_CTL(addr), oldctl);
+ outb(BAUD_MSB(addr), oldmsb);
+ return 0;
+ }
+ outb(LINE_CTL(addr), 0); /* Select INTR_ENAB */
+ if (inb(BAUD_MSB(addr)) != 0) /* Check that it has kept its value*/
+ {
+ outb(LINE_CTL(addr), oldctl);
+ outb(BAUD_MSB(addr), oldmsb);
+ return 0;
+ }
+
+ /* Com port found, now check what chip it has */
+
+ for(i = 0; i < 256; i++) /* Is there Scratch register */
+ {
+ outb(SCR(addr), i);
+ if (inb(SCR(addr)) != i)
+ break;
+ }
+ if (i == 256)
+ { /* Yes == 450 or 460 */
+ outb(SCR(addr), 0);
+ type = "82450 or 16450";
+ outb(FIFO_CTL(addr), iFIFOENA | iFIFO14CH); /* Enable fifo */
+ if ((inb(FIFO_CTL(addr)) & iFIFO14CH) != 0)
+ { /* Was it successful */
+ /* if both bits are not set then broken xx550 */
+ if ((inb(FIFO_CTL(addr)) & iFIFO14CH) == iFIFO14CH)
+ {
+ type = "82550 or 16550";
+ comfifo[unit] = TRUE;
+ }
+ else
+ {
+ type = "82550 or 16550 with non-working FIFO";
+ }
+ outb(INTR_ID(addr), 0x00); /* Disable fifos */
+ }
+ }
+ if (noisy)
+ printf("com%d: %s chip.\n", unit, type);
+ return 1;
+}
+
+/*
+ * Probe routine for use during kernel startup when it is probing
+ * all of bus_device_init
+ */
+int
+comprobe(vm_offset_t port, struct bus_ctlr *dev)
+{
+ return comprobe_general((struct bus_device *)dev, /*noisy*/ 0);
+}
+
+/*
+ * Probe routine for use by the console
+ */
+int
+comcnprobe(struct consdev *cp)
+{
+ struct bus_device *b;
+ int maj, unit, pri;
+
+#define CONSOLE_PARAMETER " console=com"
+ u_char *console = (u_char *) strstr(kernel_cmdline, CONSOLE_PARAMETER);
+
+ if (console)
+ mach_atoi(console + strlen(CONSOLE_PARAMETER), &rcline);
+
+ if (strncmp(kernel_cmdline, CONSOLE_PARAMETER + 1,
+ strlen(CONSOLE_PARAMETER) - 1) == 0)
+ mach_atoi((u_char*)kernel_cmdline + strlen(CONSOLE_PARAMETER) - 1,
+ &rcline);
+
+ maj = 0;
+ unit = -1;
+ pri = CN_DEAD;
+
+ for (b = bus_device_init; b->driver; b++)
+ if (strcmp(b->name, "com") == 0
+ && b->unit == rcline
+ && comprobe_general(b, /*quiet*/ 0))
+ {
+ /* Found one */
+ comcndev = b;
+ unit = b->unit;
+ pri = CN_REMOTE;
+ break;
+ }
+
+ cp->cn_dev = makedev(maj, unit);
+ cp->cn_pri = pri;
+
+ return 0;
+}
+
+
+/*
+ *
+ * Device Attach's are called during kernel boot, but only if the matching
+ * device Probe returned a 1.
+ *
+ */
+void
+comattach(struct bus_device *dev)
+{
+ u_char unit = dev->unit;
+ u_short addr = dev->address;
+
+ if (unit >= NCOM) {
+ printf(", disabled by NCOM configuration\n");
+ return;
+ }
+
+ take_dev_irq(dev);
+ printf(", port = %zx, spl = %zu, pic = %d. (DOS COM%d)",
+ dev->address, dev->sysdep, dev->sysdep1, unit+1);
+
+/* comcarrier[unit] = addr->flags;*/
+ commodem[unit] = 0;
+
+ outb(INTR_ENAB(addr), 0);
+ outb(MODEM_CTL(addr), 0);
+ while (!(inb(INTR_ID(addr))&1)) {
+ (void) inb(LINE_STAT (addr)); /* reset overrun error etc */
+ (void) inb(TXRX (addr)); /* reset data-ready */
+ (void) inb(MODEM_STAT(addr)); /* reset modem status reg */
+ }
+}
+
+/*
+ * Attach/init routine for console. This isn't called by
+ * configure_bus_device which sets the alive, adaptor, and minfo
+ * fields of the bus_device struct (comattach is), therefore we do
+ * that by hand.
+ */
+int
+comcninit(struct consdev *cp)
+{
+ u_char unit = comcndev->unit;
+ u_short addr = comcndev->address;
+
+ take_dev_irq(comcndev);
+
+ comcndev->alive = 1;
+ comcndev->adaptor = 0;
+ cominfo[minor(cp->cn_dev)] = comcndev;
+
+ outb(LINE_CTL(addr), iDLAB);
+ outb(BAUD_LSB(addr), divisorreg[RCBAUD] & 0xff);
+ outb(BAUD_MSB(addr), divisorreg[RCBAUD] >>8);
+ outb(LINE_CTL(addr), i8BITS);
+ outb(INTR_ENAB(addr), 0);
+ outb(MODEM_CTL(addr), iDTR|iRTS|iOUT2);
+
+ {
+ char msg[128];
+ volatile unsigned char *p = (volatile unsigned char *)phystokv(0xb8000);
+ int i;
+
+ sprintf(msg, " **** using COM port %d for console ****",
+ unit+1);
+ for (i = 0; msg[i]; i++) {
+ p[2*i] = msg[i];
+ p[2*i+1] = (0<<7) /* blink */
+ | (0x0<<4) /* bg */
+ | (1<<3) /* hi-intensity */
+ | 0x4; /* fg */
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Probe for COM<dev> after autoconfiguration.
+ * Used to handle PCMCIA modems, which may appear
+ * at any time.
+ */
+static boolean_t com_reprobe(
+ int unit)
+{
+ struct bus_device *device;
+
+ /*
+ * Look for COM device <unit> in the device
+ * initialization list. It must not be alive
+ * (otherwise we would have opened it already).
+ */
+ for (device = bus_device_init; device->driver; device++) {
+ if (device->driver == &comdriver && device->unit == unit &&
+ !device->alive && device->ctlr == (char)-1)
+ {
+ /*
+ * Found an entry for com port <unit>.
+ * Probe it.
+ */
+ if (configure_bus_device(device->name,
+ device->address,
+ device->phys_address,
+ 0,
+ "atbus"))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+io_return_t comopen(
+ dev_t dev,
+ int flag,
+ io_req_t ior)
+{
+ int unit = minor(dev);
+ u_short addr;
+ struct bus_device *isai;
+ struct tty *tp;
+ spl_t s;
+ io_return_t result;
+
+ if (unit >= NCOM)
+ return D_NO_SUCH_DEVICE; /* no such device */
+ if ((isai = cominfo[unit]) == 0 || isai->alive == 0) {
+ /*
+ * Try to probe it again
+ */
+ if (!com_reprobe(unit))
+ return D_NO_SUCH_DEVICE;
+ if ((isai = cominfo[unit]) == 0 || isai->alive == 0)
+ return D_NO_SUCH_DEVICE;
+ }
+ tp = &com_tty[unit];
+
+ if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0) {
+ ttychars(tp);
+ tp->t_addr = (char *)isai->address;
+ tp->t_dev = dev;
+ tp->t_oproc = comstart;
+ tp->t_stop = comstop;
+ tp->t_mctl = commctl;
+ tp->t_getstat = comgetstat;
+ tp->t_setstat = comsetstat;
+ if (tp->t_ispeed == 0) {
+ tp->t_ispeed = ISPEED;
+ tp->t_ospeed = ISPEED;
+ tp->t_flags = IFLAGS;
+ tp->t_state &= ~TS_BUSY;
+ }
+ }
+/*rvb tp->t_state |= TS_WOPEN; */
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ comparam(unit);
+ addr = (uintptr_t)tp->t_addr;
+
+ s = spltty();
+ if (!comcarrier[unit]) /* not originating */
+ tp->t_state |= TS_CARR_ON;
+ else {
+ int modem_stat = inb(MODEM_STAT(addr));
+ if (modem_stat & iRLSD)
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+ fix_modem_state(unit, modem_stat);
+ }
+ splx(s);
+
+ result = char_open(dev, tp, flag, ior);
+
+ if (!comtimer_active) {
+ comtimer_active = TRUE;
+ comtimer(NULL);
+ }
+
+ s = spltty();
+ while(!(inb(INTR_ID(addr))&1)) { /* while pending interrupts */
+ (void) inb(LINE_STAT (addr)); /* reset overrun error */
+ (void) inb(TXRX (addr)); /* reset data-ready */
+ (void) inb(MODEM_STAT(addr)); /* reset modem status */
+ }
+ splx(s);
+ return result;
+}
+
+void comclose(dev_t dev, int flag)
+{
+ struct tty *tp = &com_tty[minor(dev)];
+ u_short addr = (uintptr_t)tp->t_addr;
+
+ ttyclose(tp);
+ if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) {
+ outb(INTR_ENAB(addr), 0);
+ outb(MODEM_CTL(addr), 0);
+ tp->t_state &= ~TS_BUSY;
+ commodem[minor(dev)] = 0;
+ if (comfifo[minor(dev)] != 0)
+ outb(INTR_ID(addr), 0x00); /* Disable fifos */
+ }
+ return;
+}
+
+io_return_t comread(dev_t dev, io_req_t ior)
+{
+ return char_read(&com_tty[minor(dev)], ior);
+}
+
+io_return_t comwrite(dev_t dev, io_req_t ior)
+{
+ return char_write(&com_tty[minor(dev)], ior);
+}
+
+io_return_t comportdeath(dev_t dev, mach_port_t port)
+{
+ return (tty_portdeath(&com_tty[minor(dev)], (ipc_port_t)port));
+}
+
+io_return_t
+comgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data, /* pointer to OUT array */
+ mach_msg_type_number_t *count /* out */
+ )
+{
+ io_return_t result = D_SUCCESS;
+ int unit = minor(dev);
+
+ switch (flavor) {
+ case TTY_MODEM:
+ fix_modem_state(unit, inb(MODEM_STAT(cominfo[unit]->address)));
+ *data = commodem[unit];
+ *count = 1;
+ break;
+ default:
+ result = tty_get_status(&com_tty[unit], flavor, data, count);
+ break;
+ }
+ return (result);
+}
+
+io_return_t
+comsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count)
+{
+ io_return_t result = D_SUCCESS;
+ int unit = minor(dev);
+ struct tty *tp = &com_tty[unit];
+
+ switch (flavor) {
+ case TTY_SET_BREAK:
+ commctl(tp, TM_BRK, DMBIS);
+ break;
+ case TTY_CLEAR_BREAK:
+ commctl(tp, TM_BRK, DMBIC);
+ break;
+ case TTY_MODEM:
+ commctl(tp, *data, DMSET);
+ break;
+ default:
+ result = tty_set_status(&com_tty[unit], flavor, data, count);
+ if (result == D_SUCCESS && flavor == TTY_STATUS)
+ comparam(unit);
+ return (result);
+ }
+ return (D_SUCCESS);
+}
+
+void
+comintr(int unit)
+{
+ struct tty *tp = &com_tty[unit];
+ u_short addr = cominfo[unit]->address;
+ static char comoverrun = 0;
+ char c, line, intr_id;
+ int line_stat;
+
+ while (! ((intr_id=(inb(INTR_ID(addr))&MASKi)) & 1))
+ switch (intr_id) {
+ case MODi:
+ /* modem change */
+ commodem_intr(unit, inb(MODEM_STAT(addr)));
+ break;
+
+ case TRAi:
+ comtimer_state[unit] = 0;
+ tp->t_state &= ~(TS_BUSY|TS_FLUSH);
+ tt_write_wakeup(tp);
+ (void) comstart(tp);
+ break;
+ case RECi:
+ case CTIi: /* Character timeout indication */
+ if (tp->t_state&TS_ISOPEN) {
+ int escape = 0;
+ while ((line = inb(LINE_STAT(addr))) & iDR) {
+ c = inb(TXRX(addr));
+
+ if (c == 0x1b) {
+ escape = 1;
+ continue;
+ }
+
+#if MACH_KDB
+ if (escape && c == 'D'-('A'-1))
+ /* ctrl-alt-d pressed,
+ invoke debugger */
+ kdb_kintr();
+ else
+#endif /* MACH_KDB */
+ if (escape) {
+ ttyinput(0x1b, tp);
+ ttyinput(c, tp);
+ }
+ else
+ ttyinput(c, tp);
+
+ escape = 0;
+ }
+
+ if (escape)
+ /* just escape */
+ ttyinput(0x1b, tp);
+ } else
+ tt_open_wakeup(tp);
+ break;
+ case LINi:
+ line_stat = inb(LINE_STAT(addr));
+
+ if ((line_stat & iPE) &&
+ ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
+ (tp->t_flags&(EVENP|ODDP)) == ODDP)) {
+ /* parity error */;
+ } else if (line_stat&iOR && !comoverrun) {
+ printf("com%d: overrun\n", unit);
+ comoverrun = 1;
+ } else if (line_stat & (iFE | iBRKINTR)) {
+ /* framing error or break */
+ ttyinput(tp->t_breakc, tp);
+ }
+ break;
+ }
+}
+
+static void
+comparam(int unit)
+{
+ struct tty *tp = &com_tty[unit];
+ u_short addr = (uintptr_t)tp->t_addr;
+ spl_t s = spltty();
+ int mode;
+
+ if (tp->t_ispeed == B0) {
+ tp->t_state |= TS_HUPCLS;
+ outb(MODEM_CTL(addr), iOUT2);
+ commodem[unit] = 0;
+ splx(s);
+ return;
+ }
+
+ /* Do input buffering */
+ if (tp->t_ispeed >= B300)
+ tp->t_state |= TS_MIN;
+
+ outb(LINE_CTL(addr), iDLAB);
+ outb(BAUD_LSB(addr), divisorreg[tp->t_ispeed] & 0xff);
+ outb(BAUD_MSB(addr), divisorreg[tp->t_ispeed] >> 8);
+
+ if (tp->t_flags & (RAW|LITOUT|PASS8))
+ mode = i8BITS;
+ else
+ mode = i7BITS | iPEN;
+ if (tp->t_flags & EVENP)
+ mode |= iEPS;
+ if (tp->t_ispeed == B110)
+ /*
+ * 110 baud uses two stop bits -
+ * all other speeds use one
+ */
+ mode |= iSTB;
+
+ outb(LINE_CTL(addr), mode);
+
+ outb(INTR_ENAB(addr), iTX_ENAB|iRX_ENAB|iMODEM_ENAB|iERROR_ENAB);
+ if (comfifo[unit])
+ outb(FIFO_CTL(addr), iFIFOENA|iFIFO14CH);
+ outb(MODEM_CTL(addr), iDTR|iRTS|iOUT2);
+ commodem[unit] |= (TM_DTR|TM_RTS);
+ splx(s);
+}
+
+int comst_1, comst_2, comst_3, comst_4, comst_5 = 14;
+
+void
+comstart(struct tty *tp)
+{
+ int nch;
+#if 0
+ int i;
+#endif
+
+ if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) {
+comst_1++;
+ return;
+ }
+ if ((!queue_empty(&tp->t_delayed_write)) &&
+ (tp->t_outq.c_cc <= TTLOWAT(tp))) {
+comst_2++;
+ tt_write_wakeup(tp);
+ }
+ if (!tp->t_outq.c_cc) {
+comst_3++;
+ return;
+ }
+
+#if 0
+ i = (comfifo[minor(tp->t_dev)]) ? /*14*/comst_5 : 1;
+
+ tp->t_state |= TS_BUSY;
+ while (i-- > 0) {
+ nch = getc(&tp->t_outq);
+ if (nch == -1) break;
+ if ((nch & 0200) && ((tp->t_flags & LITOUT) == 0)) {
+ timeout(ttrstrt, (char *)tp, (nch & 0x7f) + 6);
+ tp->t_state |= TS_TIMEOUT;
+comst_4++;
+ return(0);
+ }
+ outb(TXRX((uintptr_t)tp->t_addr), nch);
+ }
+#else
+ nch = getc(&tp->t_outq);
+ if (nch == -1)
+ return;
+ if ((nch & 0200) && ((tp->t_flags & LITOUT) == 0)) {
+ timeout((timer_func_t *)ttrstrt, (char *)tp, (nch & 0x7f) + 6);
+ tp->t_state |= TS_TIMEOUT;
+comst_4++;
+ return;
+ }
+ outb(TXRX((uintptr_t)tp->t_addr), nch);
+ tp->t_state |= TS_BUSY;
+#endif
+}
+
+/* Check for stuck xmitters */
+int comtimer_interval = 5;
+
+void
+comtimer(void * param)
+{
+ spl_t s = spltty();
+ struct tty *tp = com_tty;
+ int i, nch;
+
+ for (i = 0; i < NCOM; i++, tp++) {
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ continue;
+ if (!tp->t_outq.c_cc)
+ continue;
+ if (++comtimer_state[i] < 2)
+ continue;
+ /* Its stuck */
+printf("Tty %p was stuck\n", tp);
+ nch = getc(&tp->t_outq);
+ outb(TXRX((uintptr_t)tp->t_addr), nch);
+ }
+
+ splx(s);
+ timeout(comtimer, 0, comtimer_interval*hz);
+}
+
+/*
+ * Set receive modem state from modem status register.
+ */
+void
+fix_modem_state(
+ int unit,
+ int modem_stat)
+{
+ int stat = 0;
+
+ if (modem_stat & iCTS)
+ stat |= TM_CTS; /* clear to send */
+ if (modem_stat & iDSR)
+ stat |= TM_DSR; /* data set ready */
+ if (modem_stat & iRI)
+ stat |= TM_RNG; /* ring indicator */
+ if (modem_stat & iRLSD)
+ stat |= TM_CAR; /* carrier? */
+
+ commodem[unit] = (commodem[unit] & ~(TM_CTS|TM_DSR|TM_RNG|TM_CAR))
+ | stat;
+}
+
+/*
+ * Modem change (input signals)
+ */
+void
+commodem_intr(
+ int unit,
+ int stat)
+{
+ int changed;
+
+ changed = commodem[unit];
+ fix_modem_state(unit, stat);
+ stat = commodem[unit];
+
+ /* Assumption: if the other party can handle
+ modem signals then it should handle all
+ the necessary ones. Else fix the cable. */
+
+ changed ^= stat; /* what changed ? */
+
+ if (changed & TM_CTS)
+ tty_cts( &com_tty[unit], stat & TM_CTS );
+
+#if 0
+ if (changed & TM_CAR)
+ ttymodem( &com_tty[unit], stat & TM_CAR );
+#endif
+
+}
+
+/*
+ * Set/get modem bits
+ */
+int
+commctl(
+ struct tty *tp,
+ int bits,
+ int how)
+{
+ spl_t s;
+ int unit;
+ vm_offset_t dev_addr;
+ int b = 0; /* Suppress gcc warning */
+
+ unit = minor(tp->t_dev);
+
+ if (bits == TM_HUP) { /* close line (internal) */
+ bits = TM_DTR | TM_RTS;
+ how = DMBIC;
+ }
+
+ if (how == DMGET) return commodem[unit];
+
+ dev_addr = cominfo[unit]->address;
+
+ s = spltty();
+
+ switch (how) {
+ case DMSET:
+ b = bits; break;
+ case DMBIS:
+ b = commodem[unit] | bits; break;
+ case DMBIC:
+ b = commodem[unit] & ~bits; break;
+ }
+ commodem[unit] = b;
+
+ if (bits & TM_BRK) {
+ if (b & TM_BRK) {
+ outb(LINE_CTL(dev_addr), inb(LINE_CTL(dev_addr)) | iSETBREAK);
+ } else {
+ outb(LINE_CTL(dev_addr), inb(LINE_CTL(dev_addr)) & ~iSETBREAK);
+ }
+ }
+
+#if 0
+ /* do I need to do something on this ? */
+ if (bits & TM_LE) { /* line enable */
+ }
+#endif
+#if 0
+ /* Unsupported */
+ if (bits & TM_ST) { /* secondary transmit */
+ }
+ if (bits & TM_SR) { /* secondary receive */
+ }
+#endif
+ if (bits & (TM_DTR|TM_RTS)) { /* data terminal ready, request to send */
+ how = iOUT2;
+ if (b & TM_DTR) how |= iDTR;
+ if (b & TM_RTS) how |= iRTS;
+ outb(MODEM_CTL(dev_addr), how);
+ }
+
+ splx(s);
+
+ /* the rest are inputs */
+ return commodem[unit];
+}
+
+void
+comstop(
+ struct tty *tp,
+ int flags)
+{
+ if ((tp->t_state & TS_BUSY) && (tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+}
+
+/*
+ *
+ * Code to be called from debugger.
+ *
+ */
+void compr_addr(vm_offset_t addr)
+{
+ /* The two line_stat prints may show different values, since
+ * touching some of the registers constitutes changing them.
+ */
+ printf("LINE_STAT(%zu) %x\n",
+ LINE_STAT(addr), inb(LINE_STAT(addr)));
+
+ printf("TXRX(%zu) %x, INTR_ENAB(%zu) %x, INTR_ID(%zu) %x, LINE_CTL(%zu) %x,\n\
+MODEM_CTL(%zu) %x, LINE_STAT(%zu) %x, MODEM_STAT(%zu) %x\n",
+ TXRX(addr), inb(TXRX(addr)),
+ INTR_ENAB(addr), inb(INTR_ENAB(addr)),
+ INTR_ID(addr), inb(INTR_ID(addr)),
+ LINE_CTL(addr), inb(LINE_CTL(addr)),
+ MODEM_CTL(addr), inb(MODEM_CTL(addr)),
+ LINE_STAT(addr), inb(LINE_STAT(addr)),
+ MODEM_STAT(addr),inb(MODEM_STAT(addr)));
+}
+
+int compr(int unit)
+{
+ compr_addr(cominfo[unit]->address);
+ return(0);
+}
+
+int
+comgetc(int unit)
+{
+ u_short addr = (u_short)(cominfo[unit]->address);
+ spl_t s = spltty();
+ int c;
+
+ while((inb(LINE_STAT(addr)) & iDR) == 0) ;
+
+ c = inb(TXRX(addr));
+ splx(s);
+ return c;
+}
+
+/*
+ * Routines for the console
+ */
+int
+comcnputc(dev_t dev, int c)
+{
+ u_short addr = (u_short)(cominfo[minor(dev)]->address);
+
+ /* Wait for transmitter to empty */
+ while((inb(LINE_STAT(addr)) & iTHRE) == 0)
+ continue;
+
+ /* send the char */
+ if (c == '\n')
+ comcnputc(dev, '\r');
+ outb(addr, c);
+
+ return 0;
+}
+
+int
+comcngetc(dev_t dev, int wait)
+{
+ u_short addr = (u_short)(cominfo[minor(dev)]->address);
+ int c;
+
+ while((inb(LINE_STAT(addr)) & iDR) == 0)
+ if (! wait)
+ return 0;
+
+ c = inb(TXRX(addr));
+ return c & 0x7f;
+}
+
+#endif /* NCOM */
diff --git a/i386/i386at/com.h b/i386/i386at/com.h
new file mode 100644
index 0000000..3be2930
--- /dev/null
+++ b/i386/i386at/com.h
@@ -0,0 +1,86 @@
+/*
+ * Communication functions
+ * Copyright (C) 2008 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, 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, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+/*
+ * Communication functions.
+ *
+ */
+
+#ifndef _COM_H_
+#define _COM_H_
+
+#include <mach/std_types.h>
+#include <device/cons.h>
+#include <device/tty.h>
+#include <chips/busses.h>
+
+/*
+ * Set receive modem state from modem status register.
+ */
+extern void fix_modem_state(int unit, int modem_stat);
+
+extern void comtimer(void * param);
+
+/*
+ * Modem change (input signals)
+ */
+extern void commodem_intr(int unit, int stat);
+
+extern int comgetc(int unit);
+
+extern int comcnprobe(struct consdev *cp);
+extern int comcninit(struct consdev *cp);
+extern int comcngetc(dev_t dev, int wait);
+extern int comcnputc(dev_t dev, int c);
+extern void comintr(int unit);
+
+int comprobe(vm_offset_t port, struct bus_ctlr *dev);
+int commctl(struct tty *tp, int bits, int how);
+void comstart(struct tty *tp);
+void comstop(struct tty *tp, int flags);
+void comattach(struct bus_device *dev);
+
+extern io_return_t
+comgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t *count);
+
+extern io_return_t
+comsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count);
+
+#if MACH_KDB
+extern void kdb_kintr(void);
+extern void compr_addr(vm_offset_t addr);
+extern int compr(int unit);
+#endif /* MACH_KDB */
+
+extern io_return_t comopen(dev_t dev, int flag, io_req_t ior);
+extern void comclose(dev_t dev, int flag);
+extern io_return_t comread(dev_t dev, io_req_t ior);
+extern io_return_t comwrite(dev_t dev, io_req_t ior);
+extern io_return_t comportdeath(dev_t dev, mach_port_t port);
+
+#endif /* _COM_H_ */
diff --git a/i386/i386at/comreg.h b/i386/i386at/comreg.h
new file mode 100644
index 0000000..7356574
--- /dev/null
+++ b/i386/i386at/comreg.h
@@ -0,0 +1,139 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 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.
+ */
+/*
+ * Olivetti serial port driver v1.0
+ * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
+ * All rights reserved.
+ *
+ */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef _COMREG_H_
+#define _COMREG_H_
+
+#define TXRX(addr) (addr + 0)
+#define BAUD_LSB(addr) (addr + 0)
+#define BAUD_MSB(addr) (addr + 1)
+#define INTR_ENAB(addr) (addr + 1)
+#define INTR_ID(addr) (addr + 2)
+#define FIFO_CTL(addr) (addr + 2)
+#define LINE_CTL(addr) (addr + 3)
+#define MODEM_CTL(addr) (addr + 4)
+#define LINE_STAT(addr) (addr + 5)
+#define MODEM_STAT(addr)(addr + 6)
+#define SCR(addr) (addr + 7)
+
+#define MODi 0
+#define TRAi 2
+#define RECi 4
+#define LINi 6
+#define CTIi 0xc
+#define MASKi 0xf
+
+/* line control register */
+#define iWLS0 0x01 /*word length select bit 0 */
+#define iWLS1 0x02 /*word length select bit 2 */
+#define iSTB 0x04 /* number of stop bits */
+#define iPEN 0x08 /* parity enable */
+#define iEPS 0x10 /* even parity select */
+#define iSP 0x20 /* stick parity */
+#define iSETBREAK 0x40 /* break key */
+#define iDLAB 0x80 /* divisor latch access bit */
+#define i5BITS 0x00 /* 5 bits per char */
+#define i6BITS 0x01 /* 6 bits per char */
+#define i7BITS 0x02 /* 7 bits per char */
+#define i8BITS 0x03 /* 8 bits per char */
+
+/* line status register */
+#define iDR 0x01 /* data ready */
+#define iOR 0x02 /* overrun error */
+#define iPE 0x04 /* parity error */
+#define iFE 0x08 /* framing error */
+#define iBRKINTR 0x10 /* a break has arrived */
+#define iTHRE 0x20 /* tx hold reg is now empty */
+#define iTSRE 0x40 /* tx shift reg is now empty */
+
+/* interrupt id regisger */
+#define iMODEM_INTR 0x01
+#define iTX_INTR 0x02
+#define iRX_INTR 0x04
+#define iERROR_INTR 0x08
+
+/* interrupt enable register */
+#define iRX_ENAB 0x01
+#define iTX_ENAB 0x02
+#define iERROR_ENAB 0x04
+#define iMODEM_ENAB 0x08
+
+/* modem control register */
+#define iDTR 0x01 /* data terminal ready */
+#define iRTS 0x02 /* request to send */
+#define iOUT1 0x04 /* COM aux line -not used */
+#define iOUT2 0x08 /* turns intr to 386 on/off */
+#define iLOOP 0x10 /* loopback for diagnostics */
+
+/* modem status register */
+#define iDCTS 0x01 /* delta clear to send */
+#define iDDSR 0x02 /* delta data set ready */
+#define iTERI 0x04 /* trail edge ring indicator */
+#define iDRLSD 0x08 /* delta rx line sig detect */
+#define iCTS 0x10 /* clear to send */
+#define iDSR 0x20 /* data set ready */
+#define iRI 0x40 /* ring indicator */
+#define iRLSD 0x80 /* rx line sig detect */
+
+/* fifo control register (only in 16550) */
+#define iFIFOENA 0x01 /* Enable fifos */
+#define iCLRRCVRFIFO 0x02 /* Clear receive fifo */
+#define iCLRXMITFIFO 0x04 /* Clear transmit fifo */
+#define iDMAMODE 0x08 /* DMA transfer enable */
+#define iFIFO1CH 0x00 /* Receive fifo trigger level 1 char */
+#define iFIFO4CH 0x40 /* Receive fifo trigger level 4 chars*/
+#define iFIFO8CH 0x80 /* Receive fifo trigger level 8 chars*/
+#define iFIFO14CH 0xc0 /* Receive fifo trigger level 14 chars*/
+
+#endif /* _COMREG_H_ */
diff --git a/i386/i386at/conf.c b/i386/i386at/conf.c
new file mode 100644
index 0000000..ecbf1e4
--- /dev/null
+++ b/i386/i386at/conf.c
@@ -0,0 +1,172 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1989 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.
+ */
+/*
+ * Device switch for i386 AT bus.
+ */
+
+#include <mach/machine/vm_types.h>
+#include <device/conf.h>
+#include <kern/mach_clock.h>
+#include <i386at/model_dep.h>
+
+#define timename "time"
+
+#ifndef MACH_HYP
+#include <i386at/kd.h>
+#define kdname "kd"
+
+#if NCOM > 0
+#include <i386at/com.h>
+#define comname "com"
+#endif /* NCOM > 0 */
+
+#if NLPR > 0
+#include <i386at/lpr.h>
+#define lprname "lpr"
+#endif /* NLPR > 0 */
+#endif /* MACH_HYP */
+
+#include <i386at/kd_event.h>
+#define kbdname "kbd"
+
+#ifndef MACH_HYP
+#include <i386at/kd_mouse.h>
+#define mousename "mouse"
+
+#include <i386at/mem.h>
+#define memname "mem"
+#endif /* MACH_HYP */
+
+#include <device/kmsg.h>
+#define kmsgname "kmsg"
+
+#ifdef MACH_HYP
+#include <xen/console.h>
+#define hypcnname "hyp"
+#endif /* MACH_HYP */
+
+#include <device/intr.h>
+#define irqname "irq"
+
+/*
+ * List of devices - console must be at slot 0
+ */
+struct dev_ops dev_name_list[] =
+{
+ /*name, open, close, read,
+ write, getstat, setstat, mmap,
+ async_in, reset, port_death, subdev,
+ dev_info */
+
+ /* We don't assign a console here, when we find one via
+ cninit() we stick something appropriate here through the
+ indirect list */
+ { "cn", nulldev_open, nulldev_close, nulldev_read,
+ nulldev_write, nulldev_getstat, nulldev_setstat, nomap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info},
+
+#ifndef MACH_HYP
+#if ENABLE_IMMEDIATE_CONSOLE
+ { "immc", nulldev_open, nulldev_close, nulldev_read,
+ nulldev_write, nulldev_getstat, nulldev_setstat,
+ nomap, nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info },
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
+ { kdname, kdopen, kdclose, kdread,
+ kdwrite, kdgetstat, kdsetstat, kdmmap,
+ nodev_async_in, nulldev_reset, kdportdeath, 0,
+ nodev_info },
+#endif /* MACH_HYP */
+
+ { timename, timeopen, timeclose, nulldev_read,
+ nulldev_write, nulldev_getstat, nulldev_setstat, timemmap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info },
+
+#ifndef MACH_HYP
+#if NCOM > 0
+ { comname, comopen, comclose, comread,
+ comwrite, comgetstat, comsetstat, nomap,
+ nodev_async_in, nulldev_reset, comportdeath, 0,
+ nodev_info },
+#endif
+
+#ifdef MACH_LPR
+ { lprname, lpropen, lprclose, lprread,
+ lprwrite, lprgetstat, lprsetstat, nomap,
+ nodev_async_in, nulldev_reset, lprportdeath, 0,
+ nodev_info },
+#endif
+
+ { mousename, mouseopen, mouseclose, mouseread,
+ nulldev_write, mousegetstat, nulldev_setstat, nomap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info },
+
+ { kbdname, kbdopen, kbdclose, kbdread,
+ nulldev_write, kbdgetstat, kbdsetstat, nomap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info },
+
+ { memname, nulldev_open, nulldev_close, nulldev_read,
+ nulldev_write, nulldev_getstat, nulldev_setstat, memmmap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info },
+#endif /* MACH_HYP */
+
+#ifdef MACH_KMSG
+ { kmsgname, kmsgopen, kmsgclose, kmsgread,
+ nulldev_write, kmsggetstat, nulldev_setstat, nomap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath, 0,
+ nodev_info },
+#endif
+
+#ifdef MACH_HYP
+ { hypcnname, hypcnopen, hypcnclose, hypcnread,
+ hypcnwrite, hypcngetstat, hypcnsetstat, nomap,
+ nodev_async_in, nulldev_reset, hypcnportdeath, 0,
+ nodev_info },
+#endif /* MACH_HYP */
+
+ { irqname, nulldev_open, nulldev_close, nulldev_read,
+ nulldev_write,nulldev_getstat,nulldev_setstat, nomap,
+ nodev_async_in, nulldev_reset, nulldev_portdeath,0,
+ nodev_info },
+
+};
+int dev_name_count = sizeof(dev_name_list)/sizeof(dev_name_list[0]);
+
+/*
+ * Indirect list.
+ */
+struct dev_indirect dev_indirect_list[] = {
+
+ /* console */
+ { "console", &dev_name_list[0], 0 }
+};
+int dev_indirect_count = sizeof(dev_indirect_list)
+ / sizeof(dev_indirect_list[0]);
diff --git a/i386/i386at/cons_conf.c b/i386/i386at/cons_conf.c
new file mode 100644
index 0000000..1d7dd38
--- /dev/null
+++ b/i386/i386at/cons_conf.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1988-1994, The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Utah $Hdr: cons_conf.c 1.7 94/12/14$
+ */
+
+/*
+ * This entire table could be autoconfig()ed but that would mean that
+ * the kernel's idea of the console would be out of sync with that of
+ * the standalone boot. I think it best that they both use the same
+ * known algorithm unless we see a pressing need otherwise.
+ */
+#include <sys/types.h>
+#include <device/cons.h>
+
+#ifdef MACH_HYP
+#include <xen/console.h>
+#else /* MACH_HYP */
+#include "kd.h"
+#if NCOM > 0
+#include "com.h"
+#endif
+#endif /* MACH_HYP */
+
+#if ENABLE_IMMEDIATE_CONSOLE
+#include "immc.h"
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
+
+/*
+ * The rest of the consdev fields are filled in by the respective
+ * cnprobe routine.
+ */
+struct consdev constab[] = {
+#ifdef MACH_HYP
+ {"hyp", hypcnprobe, hypcninit, hypcngetc, hypcnputc},
+#else /* MACH_HYP */
+#if ENABLE_IMMEDIATE_CONSOLE
+ {"immc", immc_cnprobe, immc_cninit, immc_cngetc, immc_cnputc},
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
+ {"kd", kdcnprobe, kdcninit, kdcngetc, kdcnputc},
+#if NCOM > 0
+ {"com", comcnprobe, comcninit, comcngetc, comcnputc},
+#endif
+#endif /* MACH_HYP */
+ {0}
+};
diff --git a/i386/i386at/cram.h b/i386/i386at/cram.h
new file mode 100644
index 0000000..ac40cf1
--- /dev/null
+++ b/i386/i386at/cram.h
@@ -0,0 +1,86 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+/*
+ * cram.h
+ */
+
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef _CRAM_H_
+#define _CRAM_H_
+
+/* XXX: this conflicts with read/writing the RTC */
+
+/*
+ * outb(CMOS_ADDR, addr);
+ * result = inb(CMOS_DATA);
+ *
+ * where "addr" tells what value you want to read (some are listed
+ * below). Interrupts should be disabled while you do this.
+ */
+
+/* I/O ports */
+
+#define CMOS_ADDR 0x70 /* port for CMOS ram address */
+#define CMOS_DATA 0x71 /* port for CMOS ram data */
+
+
+/* Addresses, related masks, and potential results */
+
+#define CMOS_SHUTDOWN 0xf
+#define CM_NORM_RST 0x0
+#define CM_LOAD_SYS 0x4
+#define CM_JMP_467 0xa
+
+#define CMOS_EB 0x14 /* read Equipment Byte */
+#define CM_SCRMSK 0x30 /* mask for EB query to get screen */
+#define CM_EGA_VGA 0x00 /* "not CGA or MONO" */
+#define CM_CGA_40 0x10
+#define CM_CGA_80 0x20
+#define CM_MONO_80 0x30
+
+#endif /* _CRAM_H_ */
diff --git a/i386/i386at/disk.h b/i386/i386at/disk.h
new file mode 100644
index 0000000..c558375
--- /dev/null
+++ b/i386/i386at/disk.h
@@ -0,0 +1,89 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * disk.h
+ */
+
+#ifndef _DISK_H_
+#define _DISK_H_
+
+#define V_NUMPAR 16 /* maximum number of partitions */
+
+#define VTOC_SANE 0x600DDEEE /* Indicates a sane VTOC */
+#define PDLOCATION 29 /* location of VTOC */
+
+#define LBLLOC 1 /* label block for xxxbsd */
+
+struct localpartition {
+ u_int p_flag; /*permision flags*/
+ long p_start; /*physical start sector no of partition*/
+ long p_size; /*# of physical sectors in partition*/
+};
+typedef struct localpartition localpartition_t;
+
+struct evtoc {
+ u_int fill0[6];
+ u_int cyls; /*number of cylinders per drive*/
+ u_int tracks; /*number tracks per cylinder*/
+ u_int sectors; /*number sectors per track*/
+ u_int fill1[13];
+ u_int version; /*layout version*/
+ u_int alt_ptr; /*byte offset of alternates table*/
+ u_short alt_len; /*byte length of alternates table*/
+ u_int sanity; /*to verify vtoc sanity*/
+ u_int xcyls; /*number of cylinders per drive*/
+ u_int xtracks; /*number tracks per cylinder*/
+ u_int xsectors; /*number sectors per track*/
+ u_short nparts; /*number of partitions*/
+ u_short fill2; /*pad for 286 compiler*/
+ char label[40];
+ struct localpartition part[V_NUMPAR];/*partition headers*/
+ char fill[512-352];
+};
+
+#endif /* _DISK_H_ */
diff --git a/i386/i386at/elf.h b/i386/i386at/elf.h
new file mode 100644
index 0000000..26f4d87
--- /dev/null
+++ b/i386/i386at/elf.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Richard Braun.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _X86_ELF_H
+#define _X86_ELF_H
+
+#define ELF_SHT_SYMTAB 2
+#define ELF_SHT_STRTAB 3
+
+struct elf_shdr {
+ unsigned int name;
+ unsigned int type;
+ unsigned int flags;
+ unsigned long addr;
+ unsigned long offset;
+ unsigned int size;
+ unsigned int link;
+ unsigned int info;
+ unsigned int addralign;
+ unsigned int entsize;
+};
+
+#ifdef __LP64__
+
+struct elf_sym {
+ unsigned int name;
+ unsigned char info;
+ unsigned char other;
+ unsigned short shndx;
+ unsigned long value;
+ unsigned long size;
+};
+
+#else /* __LP64__ */
+
+struct elf_sym {
+ unsigned int name;
+ unsigned long value;
+ unsigned long size;
+ unsigned char info;
+ unsigned char other;
+ unsigned short shndx;
+};
+
+#endif /* __LP64__ */
+
+#endif /* _X86_ELF_H */
diff --git a/i386/i386at/i8250.h b/i386/i386at/i8250.h
new file mode 100644
index 0000000..9b8a801
--- /dev/null
+++ b/i386/i386at/i8250.h
@@ -0,0 +1,134 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * Header file for i8250 chip
+ */
+
+#ifndef _I8250_H_
+#define _I8250_H_
+
+/* port offsets from the base i/o address */
+
+#define RDAT 0
+#define RIE 1
+#define RID 2
+#define RFC 2
+#define RLC 3
+#define RMC 4
+#define RLS 5
+#define RMS 6
+#define RDLSB 0
+#define RDMSB 1
+
+/* interrupt control register */
+
+#define IERD 0x01 /* read int */
+#define IETX 0x02 /* xmit int */
+#define IELS 0x04 /* line status int */
+#define IEMS 0x08 /* modem int */
+
+/* interrupt status register */
+
+#define IDIP 0x01 /* not interrupt pending */
+#define IDMS 0x00 /* modem int */
+#define IDTX 0x02 /* xmit int */
+#define IDRD 0x04 /* read int */
+#define IDLS 0x06 /* line status int */
+#define IDMASK 0x0f /* interrupt ID mask */
+
+/* line control register */
+
+#define LC5 0x00 /* word length 5 */
+#define LC6 0x01 /* word length 6 */
+#define LC7 0x02 /* word length 7 */
+#define LC8 0x03 /* word length 8 */
+#define LCSTB 0x04 /* 2 stop */
+#define LCPEN 0x08 /* parity enable */
+#define LCEPS 0x10 /* even parity select */
+#define LCSP 0x20 /* stick parity */
+#define LCBRK 0x40 /* send break */
+#define LCDLAB 0x80 /* divisor latch access bit */
+#define LCPAR 0x38 /* parity mask */
+
+/* line status register */
+
+#define LSDR 0x01 /* data ready */
+#define LSOR 0x02 /* overrun error */
+#define LSPE 0x04 /* parity error */
+#define LSFE 0x08 /* framing error */
+#define LSBI 0x10 /* break interrupt */
+#define LSTHRE 0x20 /* xmit holding reg empty */
+#define LSTSRE 0x40 /* xmit shift reg empty */
+
+/* modem control register */
+
+#define MCDTR 0x01 /* DTR */
+#define MCRTS 0x02 /* RTS */
+#define MCOUT1 0x04 /* OUT1 */
+#define MCOUT2 0x08 /* OUT2 */
+#define MCLOOP 0x10 /* loopback */
+
+/* modem status register */
+
+#define MSDCTS 0x01 /* delta CTS */
+#define MSDDSR 0x02 /* delta DSR */
+#define MSTERI 0x04 /* delta RE */
+#define MSDRLSD 0x08 /* delta CD */
+#define MSCTS 0x10 /* CTS */
+#define MSDSR 0x20 /* DSR */
+#define MSRI 0x40 /* RE */
+#define MSRLSD 0x80 /* CD */
+
+/* divisor latch register settings for various baud rates */
+
+#define BCNT1200 0x60
+#define BCNT2400 0x30
+#define BCNT4800 0x18
+#define BCNT9600 0x0c
+
+#endif /* _I8250_H_ */
diff --git a/i386/i386at/idt.h b/i386/i386at/idt.h
new file mode 100644
index 0000000..19e0abe
--- /dev/null
+++ b/i386/i386at/idt.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#ifndef _I386AT_IDT_
+#define _I386AT_IDT_
+
+/* There are 256 interrupt vectors on x86,
+ * the first 32 are taken by cpu faults */
+#define IDTSZ (0x100)
+
+/* PIC sits at 0x20-0x2f */
+#define PIC_INT_BASE 0x20
+
+/* IOAPIC sits at 0x30-0x47 */
+#define IOAPIC_INT_BASE 0x30
+
+/* IOAPIC spurious interrupt vector set to 0xff */
+#define IOAPIC_SPURIOUS_BASE 0xff
+
+/* Remote -> local AST requests */
+#define CALL_AST_CHECK 0xfa
+
+/* Currently for TLB shootdowns */
+#define CALL_PMAP_UPDATE 0xfb
+
+#include <i386/idt-gen.h>
+
+#ifndef __ASSEMBLER__
+extern void idt_init (void);
+extern void ap_idt_init (int cpu);
+#endif /* __ASSEMBLER__ */
+
+#endif /* _I386AT_IDT_ */
diff --git a/i386/i386at/immc.c b/i386/i386at/immc.c
new file mode 100644
index 0000000..00fc973
--- /dev/null
+++ b/i386/i386at/immc.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1995-1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#if ENABLE_IMMEDIATE_CONSOLE
+
+#include <device/cons.h>
+#include <mach/boolean.h>
+#include <i386/vm_param.h>
+#include <string.h>
+
+/* This is a special "feature" (read: kludge)
+ intended for use only for kernel debugging.
+ It enables an extremely simple console output mechanism
+ that sends text straight to CGA/EGA/VGA video memory.
+ It has the nice property of being functional right from the start,
+ so it can be used to debug things that happen very early
+ before any devices are initialized. */
+
+boolean_t immediate_console_enable = TRUE;
+
+/*
+ * XXX we assume that pcs *always* have a console
+ */
+int
+immc_cnprobe(struct consdev *cp)
+{
+ int maj, unit, pri;
+
+ maj = 0;
+ unit = 0;
+ pri = CN_INTERNAL;
+
+ cp->cn_dev = makedev(maj, unit);
+ cp->cn_pri = pri;
+ return 0;
+}
+
+int
+immc_cninit(struct consdev *cp)
+{
+ return 0;
+}
+
+int immc_cnmaygetc(void)
+{
+ return -1;
+}
+
+int
+immc_cngetc(dev_t dev, int wait)
+{
+ if (wait) {
+ int c;
+ while ((c = immc_cnmaygetc()) < 0)
+ continue;
+ return c;
+ }
+ else
+ return immc_cnmaygetc();
+}
+
+int
+immc_cnputc(dev_t dev, int c)
+{
+ static int ofs = -1;
+
+ if (!immediate_console_enable)
+ return -1;
+ if (ofs < 0 || ofs >= 80)
+ {
+ ofs = 0;
+ immc_cnputc(dev, '\n');
+ }
+
+ if (c == '\n')
+ {
+ memmove((void *) phystokv(0xb8000),
+ (void *) phystokv(0xb8000+80*2), 80*2*24);
+ memset((void *) phystokv((0xb8000+80*2*24)), 0, 80*2);
+ ofs = 0;
+ }
+ else if (c == '\r')
+ {
+ ofs = 0;
+ }
+ else if (c == '\t')
+ {
+ ofs = (ofs & ~7) + 8;
+ }
+ else
+ {
+ volatile unsigned char *p;
+
+ if (ofs >= 80)
+ {
+ immc_cnputc(dev, '\r');
+ immc_cnputc(dev, '\n');
+ }
+
+ p = (void *) phystokv(0xb8000 + 80*2*24 + ofs*2);
+ p[0] = c;
+ p[1] = 0x0f;
+ ofs++;
+ }
+ return 0;
+}
+
+void
+immc_romputc(char c)
+{
+ immc_cnputc (0, c);
+}
+
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
diff --git a/i386/i386at/immc.h b/i386/i386at/immc.h
new file mode 100644
index 0000000..dc802c8
--- /dev/null
+++ b/i386/i386at/immc.h
@@ -0,0 +1,31 @@
+/* Declarations for the immediate console.
+
+ Copyright (C) 2015 Free Software Foundation, Inc.
+
+ This file is part of the GNU Mach.
+
+ The GNU Mach 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, or (at
+ your option) any later version.
+
+ The GNU Mach 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 GNU Mach. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _IMMC_H_
+#define _IMMC_H_
+
+#include <sys/types.h>
+
+int immc_cnprobe(struct consdev *cp);
+int immc_cninit(struct consdev *cp);
+int immc_cngetc(dev_t dev, int wait);
+int immc_cnputc(dev_t dev, int c);
+void immc_romputc(char c);
+
+#endif /* _IMMC_H_ */
diff --git a/i386/i386at/int_init.c b/i386/i386at/int_init.c
new file mode 100644
index 0000000..5c8fce6
--- /dev/null
+++ b/i386/i386at/int_init.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#include <i386at/idt.h>
+#include <i386at/int_init.h>
+#include <i386/gdt.h>
+#include <i386/mp_desc.h>
+#include <kern/printf.h>
+#ifdef APIC
+#include <i386/apic.h>
+#endif
+
+/* defined in locore.S */
+extern vm_offset_t int_entry_table[];
+
+static void
+int_fill(struct real_gate *myidt)
+{
+ int i;
+#ifndef APIC
+ int base = PIC_INT_BASE;
+ int nirq = 16;
+#else
+ int base = IOAPIC_INT_BASE;
+ int nirq = NINTR;
+#endif
+
+ for (i = 0; i < nirq; i++) {
+ fill_idt_gate(myidt, base + i,
+ int_entry_table[i], KERNEL_CS,
+ ACC_PL_K|ACC_INTR_GATE, 0);
+ }
+#if NCPUS > 1
+ fill_idt_gate(myidt, CALL_AST_CHECK,
+ int_entry_table[i], KERNEL_CS,
+ ACC_PL_K|ACC_INTR_GATE, 0);
+ i++;
+ fill_idt_gate(myidt, CALL_PMAP_UPDATE,
+ int_entry_table[i], KERNEL_CS,
+ ACC_PL_K|ACC_INTR_GATE, 0);
+ i++;
+#endif
+#ifdef APIC
+ fill_idt_gate(myidt, IOAPIC_SPURIOUS_BASE,
+ int_entry_table[i], KERNEL_CS,
+ ACC_PL_K|ACC_INTR_GATE, 0);
+ i++;
+#endif
+}
+
+void
+int_init(void)
+{
+ int_fill(idt);
+}
+
+#if NCPUS > 1
+void ap_int_init(int cpu)
+{
+ int_fill(mp_desc_table[cpu]->idt);
+}
+#endif
diff --git a/i386/i386at/int_init.h b/i386/i386at/int_init.h
new file mode 100644
index 0000000..3c11ebc
--- /dev/null
+++ b/i386/i386at/int_init.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 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, 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, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+/*
+ * Initialization functions.
+ *
+ */
+
+#ifndef _INT_INIT_H_
+#define _INT_INIT_H_
+
+#include <mach/std_types.h>
+
+#ifndef __ASSEMBLER__
+extern void int_init (void);
+extern void ap_int_init (int cpu);
+#endif /* __ASSEMBLER__ */
+
+#endif /* _INT_INIT_H_ */
diff --git a/i386/i386at/interrupt.S b/i386/i386at/interrupt.S
new file mode 100644
index 0000000..77424b4
--- /dev/null
+++ b/i386/i386at/interrupt.S
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1995 Shantanu Goel
+ * 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.
+ *
+ * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ */
+
+#include <mach/machine/asm.h>
+
+#include <i386/ipl.h>
+#ifdef APIC
+# include <i386/apic.h>
+#else
+# include <i386/pic.h>
+#endif
+#include <i386/i386asm.h>
+
+#define READ_ISR (OCW_TEMPLATE|READ_NEXT_RD|READ_IS_ONRD)
+
+/*
+ * Generic interrupt handler.
+ *
+ * On entry, %eax contains the irq number.
+ *
+ * Note: kdb_kintr needs to know our stack usage
+ */
+
+#define S_REGS 28(%esp)
+#define S_RET 24(%esp)
+#define S_IRQ 20(%esp)
+#define S_IPL 16(%esp)
+
+ENTRY(interrupt)
+#ifdef APIC
+ cmpl $255,%eax /* was this a spurious intr? */
+ jne 1f
+ ret /* if so, just return */
+1:
+#endif
+ subl $24,%esp /* Two local variables + 4 parameters */
+ movl %eax,S_IRQ /* save irq number */
+
+ call spl7 /* set ipl */
+ movl %eax,S_IPL /* save previous ipl */
+
+ movl S_IRQ,%ecx /* restore irq number */
+
+#if NCPUS > 1
+ cmpl $CALL_PMAP_UPDATE,%ecx /* was this a SMP pmap_update request? */
+ je _call_single
+
+ cmpl $CALL_AST_CHECK,%ecx /* was this a SMP remote -> local ast request? */
+ je _call_local_ast
+#endif
+
+#ifndef APIC
+ movl $1,%eax
+ shll %cl,%eax /* get corresponding IRQ mask */
+ orl EXT(curr_pic_mask),%eax /* add current mask */
+
+ cmpl $8,%ecx /* do we need to ack slave? */
+ jl 1f /* no, only master */
+
+ /* EOI on slave */
+ movb %ah,%al
+ outb %al,$(PIC_SLAVE_OCW) /* mask slave out */
+
+ movb $(SPECIFIC_EOI),%al /* specific EOI for this irq */
+ andb $7,%cl /* irq number for the slave */
+ orb %cl,%al /* combine them */
+ outb %al,$(PIC_SLAVE_ICW) /* ack interrupt to slave */
+
+ movb $(SPECIFIC_EOI + I_AM_SLAVE_2),%al /* specific master EOI for cascaded slave */
+ outb %al,$(PIC_MASTER_ICW) /* ack interrupt to master */
+
+ movl EXT(curr_pic_mask),%eax /* restore original mask */
+ movb %ah,%al
+ outb %al,$(PIC_SLAVE_OCW) /* unmask slave */
+ jmp 2f
+
+1:
+ /* EOI on master */
+ outb %al,$(PIC_MASTER_OCW) /* mask master out */
+
+ movb $(SPECIFIC_EOI),%al /* specific EOI for this irq */
+ orb %cl,%al /* combine with irq number */
+ outb %al,$(PIC_MASTER_ICW) /* ack interrupt to master */
+
+ movl EXT(curr_pic_mask),%eax /* restore original mask */
+ outb %al,$(PIC_MASTER_OCW) /* unmask master */
+2:
+#else
+ movl %ecx,(%esp) /* load irq number as 1st arg */
+ call EXT(ioapic_irq_eoi) /* ioapic irq specific EOI */
+#endif
+
+ movl S_IPL,%eax
+ movl %eax,4(%esp) /* previous ipl as 2nd arg */
+
+ movl S_RET,%eax
+ movl %eax,8(%esp) /* return address as 3rd arg */
+
+ movl S_REGS,%eax
+ movl %eax,12(%esp) /* address of interrupted registers as 4th arg */
+
+ movl S_IRQ,%eax /* copy irq number */
+
+ shll $2,%eax /* irq * 4 */
+ movl EXT(iunit)(%eax),%edx /* get device unit number */
+ movl %edx,(%esp) /* unit number as 1st arg */
+
+ call *EXT(ivect)(%eax) /* call interrupt handler */
+
+_completed:
+ movl S_IPL,%eax /* restore previous ipl */
+ movl %eax,(%esp)
+ call splx_cli /* restore previous ipl */
+
+ addl $24,%esp /* pop local variables */
+ ret
+
+#if NCPUS > 1
+_call_single:
+ call EXT(lapic_eoi) /* lapic EOI before the handler to allow extra update */
+ call EXT(pmap_update_interrupt)
+ jmp _completed
+
+_call_local_ast:
+ call EXT(lapic_eoi) /* lapic EOI */
+ call EXT(ast_check) /* AST check on this cpu */
+ jmp _completed
+
+#endif
+END(interrupt)
diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c
new file mode 100644
index 0000000..2553a2c
--- /dev/null
+++ b/i386/i386at/ioapic.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2019 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Mach.
+ *
+ * GNU Mach 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, or (at your option)
+ * any later version.
+ *
+ * GNU Mach 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+#include <sys/types.h>
+#include <i386/ipl.h>
+#include <machine/irq.h>
+#include <i386/fpu.h>
+#include <i386/hardclock.h>
+#include <i386at/kd.h>
+#include <i386at/idt.h>
+#include <i386/pio.h>
+#include <i386/pit.h>
+#include <i386/pic.h> /* only for macros */
+#include <i386/smp.h>
+#include <mach/machine.h>
+#include <kern/printf.h>
+#include <kern/timer.h>
+#include <kern/lock.h>
+
+static int has_irq_specific_eoi = 0;
+int timer_pin;
+
+uint32_t lapic_timer_val = 0;
+uint32_t calibrated_ticks = 0;
+
+spl_t curr_ipl[NCPUS] = {0};
+int spl_init = 0;
+
+def_simple_lock_irq_data(static, ioapic_lock) /* Lock for non-atomic window accesses to ioapic */
+
+int iunit[NINTR] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ /* 2nd IOAPIC */
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63 };
+
+interrupt_handler_fn ivect[NINTR] = {
+ /* 00 */ (interrupt_handler_fn)hardclock,
+ /* 01 */ kdintr, /* kdintr, ... */
+ /* 02 */ intnull,
+ /* 03 */ intnull, /* lnpoll, comintr, ... */
+
+ /* 04 */ intnull, /* comintr, ... */
+ /* 05 */ intnull, /* comintr, wtintr, ... */
+ /* 06 */ intnull, /* fdintr, ... */
+ /* 07 */ intnull, /* qdintr, ... */
+
+ /* 08 */ intnull,
+ /* 09 */ intnull, /* ether */
+ /* 10 */ intnull,
+ /* 11 */ intnull,
+
+ /* 12 */ intnull,
+ /* 13 */ fpintr, /* always */
+ /* 14 */ intnull, /* hdintr, ... */
+ /* 15 */ intnull, /* ??? */
+
+ /* 16 */ intnull, /* PIRQA */
+ /* 17 */ intnull, /* PIRQB */
+ /* 18 */ intnull, /* PIRQC */
+ /* 19 */ intnull, /* PIRQD */
+ /* 20 */ intnull, /* PIRQE */
+ /* 21 */ intnull, /* PIRQF */
+ /* 22 */ intnull, /* PIRQG */
+ /* 23 */ intnull, /* PIRQH */
+
+ /* 24 */ intnull,
+ /* 25 */ intnull,
+ /* 26 */ intnull,
+ /* 27 */ intnull,
+ /* 28 */ intnull,
+ /* 29 */ intnull,
+ /* 30 */ intnull,
+ /* 31 */ intnull,
+
+ /* 32 */ intnull,
+ /* 33 */ intnull,
+ /* 34 */ intnull,
+ /* 35 */ intnull,
+ /* 36 */ intnull,
+ /* 37 */ intnull,
+ /* 38 */ intnull,
+ /* 39 */ intnull,
+ /* 40 */ intnull,
+ /* 41 */ intnull,
+ /* 42 */ intnull,
+ /* 43 */ intnull,
+ /* 44 */ intnull,
+ /* 45 */ intnull,
+ /* 46 */ intnull,
+ /* 47 */ intnull,
+ /* 48 */ intnull,
+ /* 49 */ intnull,
+ /* 50 */ intnull,
+ /* 51 */ intnull,
+ /* 52 */ intnull,
+ /* 53 */ intnull,
+ /* 54 */ intnull,
+ /* 55 */ intnull,
+
+ /* 56 */ intnull,
+ /* 57 */ intnull,
+ /* 58 */ intnull,
+ /* 59 */ intnull,
+ /* 60 */ intnull,
+ /* 61 */ intnull,
+ /* 62 */ intnull,
+ /* 63 */ intnull,
+};
+
+void
+picdisable(void)
+{
+ int i;
+
+ asm("cli");
+ for (i = 0; i < NCPUS; i++)
+ curr_ipl[i] = SPLHI;
+
+ /*
+ ** Disable PIC
+ */
+ outb ( PIC_SLAVE_OCW, PICS_MASK );
+ outb ( PIC_MASTER_OCW, PICM_MASK );
+}
+
+void
+intnull(int unit_dev)
+{
+ printf("intnull(%d)\n", unit_dev);
+}
+
+static uint32_t
+ioapic_read(uint8_t id, uint8_t reg)
+{
+ volatile ApicIoUnit *ioapic = apic_get_ioapic(id)->ioapic;
+ ioapic->select.r = reg;
+ return ioapic->window.r;
+}
+
+static void
+ioapic_write(uint8_t id, uint8_t reg, uint32_t value)
+{
+ volatile ApicIoUnit *ioapic = apic_get_ioapic(id)->ioapic;
+ ioapic->select.r = reg;
+ ioapic->window.r = value;
+}
+
+static void
+ioapic_read_entry(int apic, int pin, struct ioapic_route_entry *e)
+{
+ union ioapic_route_entry_union entry;
+
+ entry.lo = ioapic_read(apic, APIC_IO_REDIR_LOW(pin));
+ entry.hi = ioapic_read(apic, APIC_IO_REDIR_HIGH(pin));
+
+ *e = entry.both;
+}
+
+/* Write the high word first because mask bit is in low word */
+static void
+ioapic_write_entry(int apic, int pin, struct ioapic_route_entry e)
+{
+ union ioapic_route_entry_union entry = {{0, 0}};
+
+ entry.both = e;
+ ioapic_write(apic, APIC_IO_REDIR_HIGH(pin), entry.hi);
+ ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
+}
+
+/* When toggling the interrupt via mask, write low word only */
+static void
+ioapic_toggle_entry(int apic, int pin, int mask)
+{
+ union ioapic_route_entry_union entry;
+
+ spl_t s = simple_lock_irq(&ioapic_lock);
+ ioapic_read_entry(apic, pin, &entry.both);
+ entry.both.mask = mask & 0x1;
+ ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
+ simple_unlock_irq(s, &ioapic_lock);
+}
+
+static int
+ioapic_version(int apic)
+{
+ return (ioapic_read(apic, APIC_IO_VERSION) >> APIC_IO_VERSION_SHIFT) & 0xff;
+}
+
+static int
+ioapic_gsis(int apic)
+{
+ return ((ioapic_read(apic, APIC_IO_VERSION) >> APIC_IO_ENTRIES_SHIFT) & 0xff) + 1;
+}
+
+static void timer_expiry_callback(void *arg)
+{
+ volatile int *done = arg;
+ *done = 1;
+}
+
+static uint32_t
+timer_measure_10x_apic_hz(void)
+{
+ volatile int done = 0;
+ uint32_t start = 0xffffffff;
+ timer_elt_data_t tmp_timer;
+ tmp_timer.fcn = timer_expiry_callback;
+ tmp_timer.param = (void *)&done;
+
+ printf("timer calibration...");
+
+ /* Set APIC timer */
+ lapic->init_count.r = start;
+
+ /* Delay for 10 ticks (10 * 1/hz seconds) */
+ set_timeout(&tmp_timer, 10);
+ do {
+ cpu_pause();
+ } while (!done);
+
+ /* Stop APIC timer */
+ lapic->lvt_timer.r |= LAPIC_DISABLE;
+
+ printf(" done\n");
+
+ return start - lapic->cur_count.r;
+}
+
+void
+calibrate_lapic_timer(void)
+{
+ spl_t s;
+
+ /* Set one-shot timer */
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_2;
+ lapic->lvt_timer.r = IOAPIC_INT_BASE;
+
+ /* Measure number of APIC timer ticks in 10 mach ticks
+ * divide by 10 because we want to know how many in 1 tick */
+ if (!calibrated_ticks) {
+ s = splhigh();
+ spl0();
+ calibrated_ticks = timer_measure_10x_apic_hz() / 10;
+ splx(s);
+ }
+}
+
+void
+lapic_enable_timer(void)
+{
+ /* Set up counter */
+ lapic->init_count.r = calibrated_ticks;
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_2;
+
+ /* Set the timer to interrupt periodically on remapped timer GSI */
+ lapic->lvt_timer.r = IOAPIC_INT_BASE | LAPIC_TIMER_PERIODIC;
+
+ /* Some buggy hardware requires this set again */
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_2;
+
+ /* Enable interrupts for the first time */
+ printf("LAPIC timer configured on cpu%d\n", cpu_number());
+}
+
+void
+ioapic_toggle(int pin, int mask)
+{
+ int apic = 0;
+ ioapic_toggle_entry(apic, pin, mask);
+}
+
+void
+ioapic_irq_eoi(int pin)
+{
+ int apic = 0;
+ union ioapic_route_entry_union oldentry, entry;
+
+ if (pin == 0)
+ goto skip_specific_eoi;
+
+ spl_t s = simple_lock_irq(&ioapic_lock);
+
+ if (!has_irq_specific_eoi) {
+ /* Workaround for old IOAPICs with no specific EOI */
+
+ /* Mask the pin and change to edge triggered */
+ ioapic_read_entry(apic, pin, &entry.both);
+ oldentry = entry;
+ entry.both.mask = IOAPIC_MASK_DISABLED;
+ entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
+ ioapic_write_entry(apic, pin, entry.both);
+
+ /* Restore level entry */
+ ioapic_write_entry(apic, pin, oldentry.both);
+ } else {
+ volatile ApicIoUnit *ioapic = apic_get_ioapic(apic)->ioapic;
+
+ ioapic_read_entry(apic, pin, &entry.both);
+ ioapic->eoi.r = entry.both.vector;
+ }
+
+ simple_unlock_irq(s, &ioapic_lock);
+
+skip_specific_eoi:
+ lapic_eoi ();
+}
+
+static unsigned int
+override_irq(IrqOverrideData *override, union ioapic_route_entry_union *entry)
+{
+ if (override->flags & APIC_IRQ_OVERRIDE_TRIGGER_MASK) {
+ entry->both.trigger = (override->flags & APIC_IRQ_OVERRIDE_LEVEL_TRIGGERED) ?
+ IOAPIC_LEVEL_TRIGGERED : IOAPIC_EDGE_TRIGGERED;
+ } else {
+ if (override->bus == 0) {
+ /* ISA is edge-triggered by default */
+ entry->both.trigger = IOAPIC_EDGE_TRIGGERED;
+ } else {
+ entry->both.trigger = IOAPIC_LEVEL_TRIGGERED;
+ }
+ }
+
+ if (override->flags & APIC_IRQ_OVERRIDE_POLARITY_MASK) {
+ entry->both.polarity = (override->flags & APIC_IRQ_OVERRIDE_ACTIVE_LOW) ?
+ IOAPIC_ACTIVE_LOW : IOAPIC_ACTIVE_HIGH;
+ } else {
+ if (override->bus == 0) {
+ /* EISA is active-low for level-triggered interrupts */
+ if (entry->both.trigger == IOAPIC_LEVEL_TRIGGERED) {
+ entry->both.polarity = IOAPIC_ACTIVE_LOW;
+ } else {
+ entry->both.polarity = IOAPIC_ACTIVE_HIGH;
+ }
+ }
+ }
+ printf("IRQ override: pin=%d gsi=%d trigger=%s polarity=%s\n",
+ override->irq, override->gsi,
+ entry->both.trigger == IOAPIC_LEVEL_TRIGGERED ? "LEVEL" : "EDGE",
+ entry->both.polarity == IOAPIC_ACTIVE_LOW ? "LOW" : "HIGH");
+
+ return override->gsi;
+}
+
+void
+ioapic_configure(void)
+{
+ /* Assume first IO APIC maps to GSI base 0 */
+ int gsi, apic = 0, bsp = 0, pin;
+ IrqOverrideData *irq_over;
+ int timer_gsi;
+ int version = ioapic_version(apic);
+ int ngsis = ioapic_gsis(apic);
+ int ngsis2 = 0;
+
+ if (version >= 0x20) {
+ has_irq_specific_eoi = 1;
+ }
+
+ printf("IOAPIC version 0x%x\n", version);
+
+ /* Disable IOAPIC interrupts and set spurious interrupt */
+ lapic->spurious_vector.r = IOAPIC_SPURIOUS_BASE;
+
+ union ioapic_route_entry_union entry = {{0, 0}};
+
+ entry.both.delvmode = IOAPIC_FIXED;
+ entry.both.destmode = IOAPIC_PHYSICAL;
+ entry.both.mask = IOAPIC_MASK_DISABLED;
+ entry.both.dest = apic_get_cpu_apic_id(bsp);
+
+ for (pin = 0; pin < 16; pin++) {
+ gsi = pin;
+
+ /* ISA legacy IRQs */
+ entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
+ entry.both.polarity = IOAPIC_ACTIVE_HIGH;
+
+ if ((irq_over = acpi_get_irq_override(pin))) {
+ gsi = override_irq(irq_over, &entry);
+ }
+ entry.both.vector = IOAPIC_INT_BASE + gsi;
+ ioapic_write_entry(apic, pin, entry.both);
+
+ /* Timer workaround for x86 */
+ if (pin == 0) {
+ /* Save timer info */
+ timer_gsi = gsi;
+ } else {
+ /* Remap timer irq */
+ if (gsi == timer_gsi) {
+ timer_pin = pin;
+ /* Remap GSI base to timer pin so ivect[0] is the timer */
+ entry.both.vector = IOAPIC_INT_BASE;
+ ioapic_write_entry(apic, timer_pin, entry.both);
+ /* Mask the duplicate pin 0 as we will be using timer_pin */
+ mask_irq(0);
+ }
+ }
+ }
+
+ for (pin = 16; pin < ngsis; pin++) {
+ gsi = pin;
+
+ /* PCI IRQs PIRQ A-H */
+ entry.both.trigger = IOAPIC_LEVEL_TRIGGERED;
+ entry.both.polarity = IOAPIC_ACTIVE_LOW;
+
+ if ((irq_over = acpi_get_irq_override(pin))) {
+ gsi = override_irq(irq_over, &entry);
+ }
+ entry.both.vector = IOAPIC_INT_BASE + gsi;
+ ioapic_write_entry(apic, pin, entry.both);
+ }
+
+ printf("IOAPIC 0 configured with GSI 0-%d\n", ngsis - 1);
+
+ /* Second IOAPIC */
+ if (apic_get_num_ioapics() > 1) {
+ apic = 1;
+ ngsis2 = ioapic_gsis(apic);
+
+ for (pin = 0; pin < ngsis2; pin++) {
+ gsi = pin + ngsis;
+
+ /* Defaults */
+ entry.both.trigger = IOAPIC_LEVEL_TRIGGERED;
+ entry.both.polarity = IOAPIC_ACTIVE_LOW;
+
+ if ((irq_over = acpi_get_irq_override(pin + ngsis))) {
+ gsi = override_irq(irq_over, &entry);
+ }
+ entry.both.vector = IOAPIC_INT_BASE + gsi;
+ ioapic_write_entry(apic, pin, entry.both);
+ }
+
+ printf("IOAPIC 1 configured with GSI %d-%d\n", ngsis, ngsis + ngsis2 - 1);
+ }
+
+ /* Start the IO APIC receiving interrupts */
+ lapic_setup();
+ lapic_enable();
+}
diff --git a/i386/i386at/kd.c b/i386/i386at/kd.c
new file mode 100644
index 0000000..2bea3c8
--- /dev/null
+++ b/i386/i386at/kd.c
@@ -0,0 +1,3059 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+/*
+ * Olivetti Mach Console driver v0.0
+ * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
+ * All rights reserved.
+ *
+ */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/* $ Header: $ */
+
+#include <sys/types.h>
+#include <kern/debug.h>
+#include <kern/mach_clock.h>
+#include <kern/printf.h>
+#include <device/conf.h>
+#include <device/tty.h>
+#include <device/io_req.h>
+#include <device/buf.h>
+#include <vm/vm_kern.h>
+#include <i386/db_interface.h>
+#include <i386/locore.h>
+#include <i386/loose_ends.h>
+#include <i386/vm_param.h>
+#include <i386/machspl.h>
+#include <i386/pio.h>
+#include <i386at/cram.h>
+#include <i386at/kd.h>
+#include <i386at/kd_event.h>
+#include <i386at/kd_mouse.h>
+#include <i386at/kdsoft.h>
+#include <device/cons.h>
+#include <util/atoi.h>
+
+#define DEBUG 1 /* export feep() */
+
+#if 0
+#define BROKEN_KEYBOARD_RESET
+#endif
+
+struct tty kd_tty;
+extern boolean_t rebootflag;
+
+static void charput(csrpos_t pos, char ch, char chattr);
+static void charmvup(csrpos_t from, csrpos_t to, int count);
+static void charmvdown(csrpos_t from, csrpos_t to, int count);
+static void charclear(csrpos_t to, int count, char chattr);
+static void charsetcursor(csrpos_t newpos);
+static void kd_noopreset(void);
+
+/*
+ * These routines define the interface to the device-specific layer.
+ * See kdsoft.h for a more complete description of what each routine does.
+ */
+void (*kd_dput)(csrpos_t, char, char) = charput; /* put attributed char */
+void (*kd_dmvup)(csrpos_t, csrpos_t, int) = charmvup; /* block move up */
+void (*kd_dmvdown)(csrpos_t, csrpos_t, int) = charmvdown; /* block move down */
+void (*kd_dclear)(csrpos_t, int, char) = charclear; /* block clear */
+void (*kd_dsetcursor)(csrpos_t) = charsetcursor;
+ /* set cursor position on displayed page */
+void (*kd_dreset)(void) = kd_noopreset; /* prepare for reboot */
+
+/*
+ * Globals used for both character-based controllers and bitmap-based
+ * controllers. Default is EGA.
+ */
+
+vm_offset_t kd_bitmap_start = (vm_offset_t)0xa0000; /* XXX - put in kd.h */
+u_char *vid_start = (u_char *)EGA_START;
+ /* VM start of video RAM or frame buffer */
+csrpos_t kd_curpos = 0; /* set indirectly by kd_setpos--see kdsoft.h */
+short kd_lines = 25;
+short kd_cols = 80;
+char kd_attr = KA_NORMAL; /* current attribute */
+char kd_color = KA_NORMAL;
+char kd_attrflags = 0; /* Not reverse, underline, blink */
+
+/*
+ * kd_state shows the state of the modifier keys (ctrl, caps lock,
+ * etc.) It should normally be changed by calling set_kd_state(), so
+ * that the keyboard status LEDs are updated correctly.
+ */
+int kd_state = KS_NORMAL;
+int kb_mode = KB_ASCII; /* event/ascii */
+
+/*
+ * State for the keyboard "mouse".
+ */
+int kd_kbd_mouse = 0;
+int kd_kbd_magic_scale = 6;
+int kd_kbd_magic_button = 0;
+
+/*
+ * Some keyboard commands work by sending a command, waiting for an
+ * ack (handled by kdintr), then sending data, which generates a
+ * second ack. If we are in the middle of such a sequence, kd_ack
+ * shows what the ack is for.
+ *
+ * When a byte is sent to the keyboard, it is kept around in last_sent
+ * in case it needs to be resent.
+ *
+ * The rest of the variables here hold the data required to complete
+ * the sequence.
+ *
+ * XXX - the System V driver keeps a command queue, I guess in case we
+ * want to start a command while another is in progress. Is this
+ * something we should worry about?
+ */
+enum why_ack {NOT_WAITING, SET_LEDS, DATA_ACK};
+enum why_ack kd_ack = NOT_WAITING;
+
+u_char last_sent = 0;
+
+u_char kd_nextled = 0;
+
+/*
+ * We don't provide any mutex protection for this flag because we know
+ * that this module will have been initialized by the time multiple
+ * threads are running.
+ */
+boolean_t kd_initialized = FALSE; /* driver initialized? */
+boolean_t kd_extended = FALSE;
+
+/* Array for processing escape sequences. */
+#define K_MAXESC 32
+u_char esc_seq[K_MAXESC];
+u_char *esc_spt = (u_char *)0;
+
+/*
+ * This array maps scancodes to Ascii characters (or character
+ * sequences).
+ * Each row corresponds to one key. There are NUMOUTPUT bytes per key
+ * state. The states are ordered: Normal, SHIFT, CTRL, ALT,
+ * SHIFT/ALT.
+ */
+
+/* This new keymap from Tudor Hulubei (tudor@cs.unh.edu) makes the
+ following changes to the keyboard driver:
+
+ - Alt + key (m-key) returns `ESC key' instead of `ESC N key'.
+ - Backspace returns 0x7f instead of 0x08.
+ - Delete returns `ESC [ 9' instead of 0x7f.
+ - Alt + function keys return key sequences that are different
+ from the key sequences returned by the function keys alone.
+ This is done with the idea of allowing a terminal server to
+ implement multiple virtual consoles mapped on Alt+F1, Alt+F2,
+ etc, as in Linux.
+
+ -- Derek Upham 1997/06/25 */
+
+unsigned char key_map[NUMKEYS][WIDTH_KMAP] = {
+{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC},
+{K_ESC,NC,NC, K_ESC,NC,NC, K_ESC,NC,NC, 0x1b,K_ESC,NC, K_ESC,NC,NC},
+{K_ONE,NC,NC, K_BANG,NC,NC, K_ONE,NC,NC, 0x1b,K_ONE,NC, 0x1b,0x4e,K_BANG},
+{K_TWO,NC,NC, K_ATSN,NC,NC, K_NUL,NC,NC, 0x1b,K_TWO,NC, 0x1b,0x4e,K_ATSN},
+{K_THREE,NC,NC, K_POUND,NC,NC, K_THREE,NC,NC, 0x1b,K_THREE,NC, 0x1b,0x4e,K_POUND},
+{K_FOUR,NC,NC, K_DOLLAR,NC,NC, K_FOUR,NC,NC, 0x1b,K_FOUR,NC, 0x1b,0x4e,K_DOLLAR},
+{K_FIVE,NC,NC, K_PERC,NC,NC, K_FIVE,NC,NC, 0x1b,K_FIVE,NC, 0x1b,0x4e,K_PERC},
+{K_SIX,NC,NC, K_CARET,NC,NC, K_RS,NC,NC, 0x1b,K_SIX,NC, 0x1b,0x4e,K_CARET},
+{K_SEVEN,NC,NC, K_AMPER,NC,NC, K_SEVEN,NC,NC, 0x1b,K_SEVEN,NC, 0x1b,0x4e,K_AMPER},
+{K_EIGHT,NC,NC, K_ASTER,NC,NC, K_EIGHT,NC,NC, 0x1b,K_EIGHT,NC, 0x1b,0x4e,K_ASTER},
+{K_NINE,NC,NC, K_LPAREN,NC,NC, K_NINE,NC,NC, 0x1b,K_NINE,NC, 0x1b,0x4e,K_LPAREN},
+{K_ZERO,NC,NC, K_RPAREN,NC,NC, K_ZERO,NC,NC, 0x1b,K_ZERO,NC, 0x1b,0x4e,K_RPAREN},
+{K_MINUS,NC,NC, K_UNDSC,NC,NC, K_US,NC,NC, 0x1b,K_MINUS,NC, 0x1b,0x4e,K_UNDSC},
+{K_EQL,NC,NC, K_PLUS,NC,NC, K_EQL,NC,NC, 0x1b,K_EQL,NC, 0x1b,0x4e,K_PLUS},
+{K_DEL,NC,NC, K_DEL,NC,NC, K_DEL,NC,NC, 0x1b,K_DEL,NC, K_DEL,NC,NC},
+{K_HT,NC,NC, K_GS,NC,NC, K_HT,NC,NC, 0x1b,K_HT,NC, K_GS,NC,NC},
+{K_q,NC,NC, K_Q,NC,NC, K_DC1,NC,NC, 0x1b,K_q,NC, 0x1b,0x4e,K_Q},
+{K_w,NC,NC, K_W,NC,NC, K_ETB,NC,NC, 0x1b,K_w,NC, 0x1b,0x4e,K_W},
+{K_e,NC,NC, K_E,NC,NC, K_ENQ,NC,NC, 0x1b,K_e,NC, 0x1b,0x4e,K_E},
+{K_r,NC,NC, K_R,NC,NC, K_DC2,NC,NC, 0x1b,K_r,NC, 0x1b,0x4e,K_R},
+{K_t,NC,NC, K_T,NC,NC, K_DC4,NC,NC, 0x1b,K_t,NC, 0x1b,0x4e,K_T},
+{K_y,NC,NC, K_Y,NC,NC, K_EM,NC,NC, 0x1b,K_y,NC, 0x1b,0x4e,K_Y},
+{K_u,NC,NC, K_U,NC,NC, K_NAK,NC,NC, 0x1b,K_u,NC, 0x1b,0x4e,K_U},
+{K_i,NC,NC, K_I,NC,NC, K_HT,NC,NC, 0x1b,K_i,NC, 0x1b,0x4e,K_I},
+{K_o,NC,NC, K_O,NC,NC, K_SI,NC,NC, 0x1b,K_o,NC, 0x1b,0x4e,K_O},
+{K_p,NC,NC, K_P,NC,NC, K_DLE,NC,NC, 0x1b,K_p,NC, 0x1b,0x4e,K_P},
+{K_LBRKT,NC,NC, K_LBRACE,NC,NC, K_ESC,NC,NC, 0x1b,K_LBRKT,NC, 0x1b,0x4e,K_LBRACE},
+{K_RBRKT,NC,NC, K_RBRACE,NC,NC, K_GS,NC,NC, 0x1b,K_RBRKT,NC, 0x1b,0x4e,K_RBRACE},
+{K_CR,NC,NC, K_CR,NC,NC, K_CR,NC,NC, 0x1b,K_CR,NC, K_CR,NC,NC},
+{K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC, K_SCAN,K_CTLSC,NC},
+{K_a,NC,NC, K_A,NC,NC, K_SOH,NC,NC, 0x1b,K_a,NC, 0x1b,0x4e,K_A},
+{K_s,NC,NC, K_S,NC,NC, K_DC3,NC,NC, 0x1b,K_s,NC, 0x1b,0x4e,K_S},
+{K_d,NC,NC, K_D,NC,NC, K_EOT,NC,NC, 0x1b,K_d,NC, 0x1b,0x4e,K_D},
+{K_f,NC,NC, K_F,NC,NC, K_ACK,NC,NC, 0x1b,K_f,NC, 0x1b,0x4e,K_F},
+{K_g,NC,NC, K_G,NC,NC, K_BEL,NC,NC, 0x1b,K_g,NC, 0x1b,0x4e,K_G},
+{K_h,NC,NC, K_H,NC,NC, K_BS,NC,NC, 0x1b,K_h,NC, 0x1b,0x4e,K_H},
+{K_j,NC,NC, K_J,NC,NC, K_LF,NC,NC, 0x1b,K_j,NC, 0x1b,0x4e,K_J},
+{K_k,NC,NC, K_K,NC,NC, K_VT,NC,NC, 0x1b,K_k,NC, 0x1b,0x4e,K_K},
+{K_l,NC,NC, K_L,NC,NC, K_FF,NC,NC, 0x1b,K_l,NC, 0x1b,0x4e,K_L},
+{K_SEMI,NC,NC, K_COLON,NC,NC, K_SEMI,NC,NC, 0x1b,K_SEMI,NC, 0x1b,0x4e,K_COLON},
+{K_SQUOTE,NC,NC,K_DQUOTE,NC,NC, K_SQUOTE,NC,NC,0x1b,K_SQUOTE,NC, 0x1b,0x4e,K_DQUOTE},
+{K_GRAV,NC,NC, K_TILDE,NC,NC, K_RS,NC,NC, 0x1b,K_GRAV,NC, 0x1b,0x4e,K_TILDE},
+{K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC, K_SCAN,K_LSHSC,NC},
+{K_BSLSH,NC,NC, K_PIPE,NC,NC, K_FS,NC,NC, 0x1b,K_BSLSH,NC, 0x1b,0x4e,K_PIPE},
+{K_z,NC,NC, K_Z,NC,NC, K_SUB,NC,NC, 0x1b,K_z,NC, 0x1b,0x4e,K_Z},
+{K_x,NC,NC, K_X,NC,NC, K_CAN,NC,NC, 0x1b,K_x,NC, 0x1b,0x4e,K_X},
+{K_c,NC,NC, K_C,NC,NC, K_ETX,NC,NC, 0x1b,K_c,NC, 0x1b,0x4e,K_C},
+{K_v,NC,NC, K_V,NC,NC, K_SYN,NC,NC, 0x1b,K_v,NC, 0x1b,0x4e,K_V},
+{K_b,NC,NC, K_B,NC,NC, K_STX,NC,NC, 0x1b,K_b,NC, 0x1b,0x4e,K_B},
+{K_n,NC,NC, K_N,NC,NC, K_SO,NC,NC, 0x1b,K_n,NC, 0x1b,0x4e,K_N},
+{K_m,NC,NC, K_M,NC,NC, K_CR,NC,NC, 0x1b,K_m,NC, 0x1b,0x4e,K_M},
+{K_COMMA,NC,NC, K_LTHN,NC,NC, K_COMMA,NC,NC, 0x1b,K_COMMA,NC, 0x1b,0x4e,K_LTHN},
+{K_PERIOD,NC,NC,K_GTHN,NC,NC, K_PERIOD,NC,NC,0x1b,K_PERIOD,NC, 0x1b,0x4e,K_GTHN},
+{K_SLASH,NC,NC, K_QUES,NC,NC, K_SLASH,NC,NC, 0x1b,K_SLASH,NC, 0x1b,0x4e,K_QUES},
+{K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC, K_SCAN,K_RSHSC,NC},
+{K_ASTER,NC,NC, K_ASTER,NC,NC, K_ASTER,NC,NC, 0x1b,K_ASTER,NC, 0x1b,0x4e,K_ASTER},
+{K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC, K_SCAN,K_ALTSC,NC},
+{K_SPACE,NC,NC, K_SPACE,NC,NC, K_NUL,NC,NC, 0x1b,K_SPACE,NC, K_SPACE,NC,NC},
+{K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC, K_SCAN,K_CLCKSC,NC},
+{K_F1, K_F1S, K_F1, K_F1A, K_F1S},
+{K_F2, K_F2S, K_F2, K_F2A, K_F2S},
+{K_F3, K_F3S, K_F3, K_F3A, K_F3S},
+{K_F4, K_F4S, K_F4, K_F4A, K_F4S},
+{K_F5, K_F5S, K_F5, K_F5A, K_F5S},
+{K_F6, K_F6S, K_F6, K_F6A, K_F6S},
+{K_F7, K_F7S, K_F7, K_F7A, K_F7S},
+{K_F8, K_F8S, K_F8, K_F8A, K_F8S},
+{K_F9, K_F9S, K_F9, K_F9A, K_F9S},
+{K_F10, K_F10S, K_F10, K_F10A, K_F10S},
+{K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC, K_SCAN,K_NLCKSC,NC},
+{K_SCRL, K_NUL,NC,NC, K_SCRL, K_SCRL, K_NUL,NC,NC},
+{K_HOME, K_SEVEN,NC,NC, K_HOME, K_HOME, 0x1b,0x4e,K_SEVEN},
+{K_UA, K_EIGHT,NC,NC, K_UA, K_UA, 0x1b,0x4e,K_EIGHT},
+{K_PUP, K_NINE,NC,NC, K_PUP, K_PUP, 0x1b,0x4e,K_NINE},
+{0x1b,0x5b,0x53, K_MINUS,NC,NC, 0x1b,0x5b,0x53, 0x1b,0x5b,0x53, 0x1b,0x4e,0x2d},
+{K_LA, K_FOUR,NC,NC, K_LA, K_LA, 0x1b,0x4e,K_FOUR},
+{0x1b,0x5b,0x47, K_FIVE,NC,NC, 0x1b,0x5b,0x47, 0x1b,0x5b,0x47, 0x1b,0x4e,0x35},
+{K_RA, K_SIX,NC,NC, K_RA, K_RA, 0x1b,0x4e,K_SIX},
+{0x1b,0x5b,0x54, K_PLUS,NC,NC, 0x1b,0x5b,0x54, 0x1b,0x5b,0x54, 0x1b,0x4e,0x2b},
+{K_END, K_ONE,NC,NC, K_END, K_END, 0x1b,0x4e,K_ONE},
+{K_DA, K_TWO,NC,NC, K_DA, K_DA, 0x1b,0x4e,K_TWO},
+{K_PDN, K_THREE,NC,NC, K_PDN, K_PDN, 0x1b,0x4e,K_THREE},
+{K_INS, K_ZERO,NC,NC, K_INS, K_INS, 0x1b,0x4e,K_ZERO},
+{0x1b,0x5b,0x39, K_PERIOD,NC,NC, K_DEL,NC,NC, K_DEL,NC,NC, 0x1b,0x4e,K_PERIOD},
+{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC},
+{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC},
+{NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC, NC,NC,NC},
+{K_F11, K_F11S, K_F11, K_F11A, K_F11S},
+{K_F12, K_F12S, K_F12, K_F12A, K_F12S}
+};
+
+
+/*
+ * Globals used only for character-based controllers.
+ */
+
+short kd_index_reg = EGA_IDX_REG;
+short kd_io_reg = EGA_IO_REG;
+
+
+/*
+ * Globals used only for bitmap-based controllers. See kdsoft.h for
+ * an explanation of what some of these variables are used for.
+ */
+
+u_char *font_start = 0; /* starting addr of font */
+
+short fb_width = 0; /* bits in frame buffer scan line */
+short fb_height = 0; /* scan lines in frame buffer*/
+short char_width = 0; /* bit width of 1 char */
+short char_height = 0; /* bit height of 1 char */
+short chars_in_font = 0;
+short cursor_height = 0; /* bit height of cursor */
+
+/* These initial values are simply guesses. */
+u_char char_black = 0;
+u_char char_white = 0xff;
+
+short xstart = 0;
+short ystart = 0;
+
+short char_byte_width = 0; /* char_width/NBBY */
+short fb_byte_width = 0; /* fb_width/NBBY */
+short font_byte_width = 0; /* num bytes in 1 scan line of font */
+
+/*
+ * Switch for poll vs. interrupt.
+ */
+int kd_pollc = 0;
+
+#ifdef DEBUG
+static void
+pause(void)
+{
+ int i;
+
+ for (i = 0; i < 50000; ++i)
+ ;
+}
+
+/*
+ * feep:
+ *
+ * Ring the bell for a short time.
+ * Warning: uses outb(). You may prefer to use kd_debug_put.
+ */
+void
+feep(void)
+{
+ kd_bellon();
+ pause();
+ kd_belloff(NULL);
+}
+
+/*
+ * Put a debugging character on the screen.
+ * LOC=0 means put it in the bottom right corner, LOC=1 means put it
+ * one column to the left, etc.
+ */
+void
+kd_debug_put(
+ int loc,
+ char c)
+{
+ csrpos_t pos = ONE_PAGE - (loc+1) * ONE_SPACE;
+
+ (*kd_dput)(pos, c, KA_NORMAL);
+}
+#endif /* DEBUG */
+
+
+extern boolean_t mouse_in_use;
+int old_kb_mode;
+
+void
+cnpollc(boolean_t on)
+{
+ if (mouse_in_use) {
+ if (on) {
+ /* switch into X */
+ old_kb_mode = kb_mode;
+ kb_mode = KB_ASCII;
+ X_kdb_enter();
+
+ kd_pollc++;
+ } else {
+ --kd_pollc;
+
+ /* switch out of X */
+ X_kdb_exit();
+ kb_mode = old_kb_mode;
+ }
+ } else {
+ if (on) {
+ kd_pollc++;
+ } else {
+ --kd_pollc;
+ }
+ }
+}
+
+
+
+/*
+ * kdopen:
+ *
+ * This opens the console driver and sets up the tty and other
+ * rudimentary stuff including calling the line discipline for
+ * setting up the device independent stuff for a tty driver.
+ *
+ * input: device number 'dev', and flag
+ *
+ * output: device is opened and setup
+ *
+ */
+int
+kdopen(
+ dev_t dev,
+ int flag,
+ io_req_t ior)
+{
+ struct tty *tp;
+ spl_t o_pri;
+
+ tp = &kd_tty;
+ o_pri = simple_lock_irq(&tp->t_lock);
+ if (!(tp->t_state & (TS_ISOPEN|TS_WOPEN))) {
+ /* XXX ttychars allocates memory */
+ simple_unlock_nocheck(&tp->t_lock.slock);
+ ttychars(tp);
+ simple_lock_nocheck(&tp->t_lock.slock);
+ /*
+ * Special support for boot-time rc scripts, which don't
+ * stty the console.
+ */
+ tp->t_oproc = kdstart;
+ tp->t_stop = kdstop;
+ tp->t_ospeed = tp->t_ispeed = B115200;
+ tp->t_flags = ODDP|EVENP|ECHO|CRMOD|XTABS|LITOUT;
+ kdinit();
+ }
+ tp->t_state |= TS_CARR_ON;
+ simple_unlock_irq(o_pri, &tp->t_lock);
+ return (char_open(dev, tp, flag, ior));
+}
+
+
+/*
+ * kdclose:
+ *
+ * This function merely executes the device independent code for
+ * closing the line discipline.
+ *
+ * input: device number 'dev', and flag
+ *
+ * output: device is closed
+ *
+ */
+/*ARGSUSED*/
+void
+kdclose(dev_t dev, int flag)
+{
+ struct tty *tp;
+
+ tp = &kd_tty;
+ {
+ spl_t s;
+ s = simple_lock_irq(&tp->t_lock);
+ ttyclose(tp);
+ simple_unlock_irq(s, &tp->t_lock);
+ }
+
+ return;
+}
+
+
+/*
+ * kdread:
+ *
+ * This function executes the device independent code to read from
+ * the tty.
+ *
+ * input: device number 'dev'
+ *
+ * output: characters are read from tty clists
+ *
+ */
+/*ARGSUSED*/
+int
+kdread(dev_t dev, io_req_t uio)
+{
+ struct tty *tp;
+
+ tp = &kd_tty;
+ tp->t_state |= TS_CARR_ON;
+ return((*linesw[kd_tty.t_line].l_read)(tp, uio));
+}
+
+
+/*
+ * kdwrite:
+ *
+ * This function does the device independent write action for this
+ * console (tty) driver.
+ *
+ * input: device number 'dev'
+ *
+ * output: characters are written to tty clists
+ *
+ */
+/*ARGSUSED*/
+int
+kdwrite(dev_t dev, io_req_t uio)
+{
+ return((*linesw[kd_tty.t_line].l_write)(&kd_tty, uio));
+}
+
+/*
+ * Mmap.
+ */
+
+/*ARGSUSED*/
+vm_offset_t
+kdmmap(dev_t dev, vm_offset_t off, vm_prot_t prot)
+{
+ if (off >= (128*1024))
+ return(-1);
+
+ /* Get page frame number for the page to be mapped. */
+ return(i386_btop(kd_bitmap_start+off));
+}
+
+int
+kdportdeath(
+ dev_t dev,
+ mach_port_t port)
+{
+ return (tty_portdeath(&kd_tty, (ipc_port_t)port));
+}
+
+/*ARGSUSED*/
+io_return_t kdgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data, /* pointer to OUT array */
+ mach_msg_type_number_t *count) /* OUT */
+{
+ io_return_t result;
+
+ switch (flavor) {
+ case KDGSTATE:
+ if (*count < 1)
+ return (D_INVALID_OPERATION);
+ *data = kd_state;
+ *count = 1;
+ result = D_SUCCESS;
+ break;
+
+ case KDGKBENT:
+ result = kdgetkbent((struct kbentry *)data);
+ *count = sizeof(struct kbentry)/sizeof(int);
+ break;
+
+ default:
+ result = tty_get_status(&kd_tty, flavor, data, count);
+ break;
+ }
+ return (result);
+}
+
+/*ARGSUSED*/
+io_return_t kdsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count)
+{
+ io_return_t result;
+
+ switch (flavor) {
+ case KDSKBENT:
+ if (count < sizeof(struct kbentry)/sizeof(int)) {
+ return (D_INVALID_OPERATION);
+ }
+ result = kdsetkbent((struct kbentry *)data, 0);
+ break;
+
+ case KDSETBELL:
+ if (count < 1)
+ return (D_INVALID_OPERATION);
+ result = kdsetbell(*data, 0);
+ break;
+
+ default:
+ result = tty_set_status(&kd_tty, flavor, data, count);
+ }
+ return (result);
+}
+
+
+
+/*
+ * kdsetbell:
+ *
+ * Turn the bell on or off. Returns error code, if given bogus
+ * on/off value.
+ */
+int
+kdsetbell(
+ int val, /* on or off */
+ int flags) /* flags set for console */
+{
+ int err = 0;
+
+ if (val == KD_BELLON)
+ kd_bellon();
+ else if (val == KD_BELLOFF)
+ kd_belloff(NULL);
+ else
+ err = D_INVALID_OPERATION;
+
+ return(err);
+}
+
+/*
+ * kdgetkbent:
+ *
+ * Get entry from key mapping table. Returns error code, if any.
+ */
+int
+kdgetkbent(struct kbentry *kbent)
+{
+ u_char *cp;
+ spl_t o_pri = SPLKD(); /* probably superfluous */
+
+ cp = &key_map[kbent->kb_index][CHARIDX(kbent->kb_state)];
+ kbent->kb_value[0] = *cp++;
+ kbent->kb_value[1] = *cp++;
+ kbent->kb_value[2] = *cp;
+ (void)splx(o_pri);
+ return(0);
+}
+
+
+/*
+ * kdsetkbent:
+ *
+ * Set entry in key mapping table. Return error code, if any.
+ */
+int
+kdsetkbent(
+ struct kbentry *kbent,
+ int flags) /* flags set for console */
+{
+ u_char *cp;
+ spl_t o_pri;
+
+ o_pri = SPLKD();
+ cp = &key_map[kbent->kb_index][CHARIDX(kbent->kb_state)];
+ *cp++ = kbent->kb_value[0];
+ *cp++ = kbent->kb_value[1];
+ *cp = kbent->kb_value[2];
+ (void)splx(o_pri);
+ return(0);
+}
+
+/*
+ * kdintr:
+ *
+ * This function is the interrupt code for the driver. Since this is
+ * a special tty (console), interrupts are only for input, so we read in
+ * the character. If in ascii mode, we then do the mapping translation
+ * from the keyboard switch table and place the characters on the tty's
+ * input switch table. If in event mode, we create and queue a kd_event.
+ *
+ * input: interrupt vector 'vec'
+ *
+ * output: character or sequence is placed on appropriate queue
+ *
+ */
+/*ARGSUSED*/
+void
+kdintr(int vec)
+{
+ struct tty *tp;
+ unsigned char c;
+ unsigned char scancode;
+ unsigned int char_idx;
+ boolean_t up = FALSE; /* key-up event */
+
+ if (kd_pollc)
+ return; /* kdb polling kbd */
+
+ if (!kd_initialized)
+ return;
+
+ tp = &kd_tty;
+#ifdef old
+ while ((inb(K_STATUS) & K_OBUF_FUL) == 0)
+ ; /* this should never loop */
+#else /* old */
+ {
+ /*
+ * Allow for keyboards that raise interrupt before
+ * the character gets to the buffer. But don't wait
+ * forever if grabbing the character by polling leaves
+ * the interrupt on but buffer empty.
+ */
+ /*
+ * Micronics VLB motherboard with 486DX2 can report keyboard
+ * interrupt before K_STATUS register indicates that the
+ * output buffer is full. Moreover, the bus won't settle w
+ * while we poll K_STATUS at speed. Temporary fix is to break
+ * out after safety runs out and pick up keyboard event. This
+ * should be fixed eventually by putting a 1us timout between
+ * inb's to K_STATUS and fix the pic initialization order to
+ * avoid bootup keyboard wedging (ie make kd a real device)
+ */
+ int safety = 1000;
+ while ((inb(K_STATUS) & K_OBUF_FUL) == 0)
+ if (!safety--) break; /* XXX */
+ }
+#endif /* old */
+ /*
+ * We may have seen a mouse event.
+ */
+ if ((inb(K_STATUS) & 0x20) == 0x20) {
+ if (mouse_in_use) {
+ mouse_handle_byte((u_char)inb(K_RDWR));
+ return;
+ } else {
+ printf("M%xI", inb(K_RDWR));
+ return;
+ }
+ }
+
+ scancode = inb(K_RDWR);
+ if (scancode == K_EXTEND && kb_mode != KB_EVENT) {
+ kd_extended = TRUE;
+ goto done;
+ } else if (scancode == K_RESEND) {
+ kd_resend();
+ goto done;
+ } else if (scancode == K_ACKSC) {
+ kd_handle_ack();
+ goto done;
+ } else if (kd_kbd_mouse && kd_kbd_magic(scancode)) {
+ goto done;
+ } else if (kdcheckmagic(scancode)) {
+ goto done;
+ } else if (kb_mode == KB_EVENT) {
+ kd_enqsc(scancode);
+ goto done;
+ } /* else... */
+
+ if (scancode & K_UP) {
+ up = TRUE;
+ scancode &= ~K_UP;
+ }
+ if (scancode < NUMKEYS) {
+ /* Lookup in map, then process. */
+ char_idx = kdstate2idx(kd_state, kd_extended);
+ c = key_map[scancode][char_idx];
+ if (c == K_SCAN) {
+ c = key_map[scancode][++char_idx];
+ set_kd_state(do_modifier(kd_state, c, up));
+ } else if (!up) {
+ /* regular key-down */
+ unsigned int max; /* max index for char sequence */
+
+ max = char_idx + NUMOUTPUT;
+ char_idx++;
+ if (!kd_extended) {
+ if (kd_state&KS_CLKED) {
+ if (kd_isupper(c)) {
+ c += ('a' - 'A');
+ max = char_idx;
+ }
+ else if (kd_islower(c)) {
+ c -= ('a' - 'A');
+ max = char_idx;
+ }
+ }
+ /*
+ * Notice that even if the keypad is remapped,
+ * NumLock only effects the keys that are
+ * physically part of the keypad. Is this
+ * The Right Thing?
+ */
+ if ((kd_state&KS_NLKED) &&
+ (((K_HOMESC) <= scancode) &&
+ (scancode <= (K_DELSC)))) {
+ char_idx = CHARIDX(SHIFT_STATE);
+ c = key_map[scancode][char_idx];
+ max = char_idx + NUMOUTPUT;
+ char_idx++;
+ }
+ }
+
+ /*
+ * here's where we actually put the char (or
+ * char sequence, for function keys) onto the
+ * input queue.
+ */
+ for ( ; (c != K_DONE) && (char_idx <= max);
+ c = key_map[scancode][char_idx++]) {
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ kd_extended = FALSE;
+ }
+ }
+
+ done:
+ return;
+}
+
+/*
+ * kd_handle_ack:
+ *
+ * For pending commands, complete the command. For data bytes,
+ * drop the ack on the floor.
+ */
+void
+kd_handle_ack(void)
+{
+ switch (kd_ack) {
+ case SET_LEDS:
+ kd_setleds2();
+ kd_ack = DATA_ACK;
+ break;
+ case DATA_ACK:
+ kd_ack = NOT_WAITING;
+ break;
+ case NOT_WAITING:
+ printf("unexpected ACK from keyboard\n");
+ break;
+ default:
+ panic("bogus kd_ack\n");
+ break;
+ }
+}
+
+/*
+ * kd_resend:
+ *
+ * Resend a missed keyboard command or data byte.
+ */
+void
+kd_resend(void)
+{
+ if (kd_ack == NOT_WAITING)
+ printf("unexpected RESEND from keyboard\n");
+ else
+ kd_senddata(last_sent);
+}
+
+
+/*
+ * do_modifier:
+ *
+ * Change keyboard state according to which modifier key and
+ * whether it went down or up.
+ *
+ * input: the current state, the key, and the key's direction.
+ * The key can be any key, not just a modifier key.
+ *
+ * output: the new state
+ */
+int
+do_modifier(
+ int state,
+ Scancode c,
+ boolean_t up)
+{
+ switch (c) {
+ case (K_ALTSC):
+ if (up)
+ state &= ~KS_ALTED;
+ else
+ state |= KS_ALTED;
+ kd_extended = FALSE;
+ break;
+#ifndef ORC
+ case (K_CLCKSC):
+#endif /* ORC */
+ case (K_CTLSC):
+ if (up)
+ state &= ~KS_CTLED;
+ else
+ state |= KS_CTLED;
+ kd_extended = FALSE;
+ break;
+#ifdef ORC
+ case (K_CLCKSC):
+ if (!up)
+ state ^= KS_CLKED;
+ break;
+#endif /* ORC */
+ case (K_NLCKSC):
+ if (!up)
+ state ^= KS_NLKED;
+ break;
+ case (K_LSHSC):
+ case (K_RSHSC):
+ if (up)
+ state &= ~KS_SHIFTED;
+ else
+ state |= KS_SHIFTED;
+ kd_extended = FALSE;
+ break;
+ }
+
+ return(state);
+}
+
+
+/*
+ * kdcheckmagic:
+ *
+ * Check for magic keystrokes for invoking the debugger or
+ * rebooting or ...
+ *
+ * input: an unprocessed scancode
+ *
+ * output: TRUE if a magic key combination was recognized and
+ * processed. FALSE otherwise.
+ *
+ * side effects:
+ * various actions possible, depending on which keys are
+ * pressed. If the debugger is called, steps are taken
+ * to ensure that the system doesn't think the magic keys
+ * are still held down.
+ */
+boolean_t
+kdcheckmagic(Scancode scancode)
+{
+ static int magic_state = KS_NORMAL; /* like kd_state */
+ boolean_t up = FALSE;
+
+ if (scancode == 0x46) /* scroll lock */
+/* if (scancode == 0x52) ** insert key */
+ {
+ kd_kbd_mouse = !kd_kbd_mouse;
+ kd_kbd_magic_button = 0;
+ return(TRUE);
+ }
+ if (scancode & K_UP) {
+ up = TRUE;
+ scancode &= ~K_UP;
+ }
+ magic_state = do_modifier(magic_state, scancode, up);
+
+ if ((magic_state&(KS_CTLED|KS_ALTED)) == (KS_CTLED|KS_ALTED)) {
+ switch (scancode) {
+#if MACH_KDB
+ case K_dSC: /* ctl-alt-d */
+ kdb_kintr(); /* invoke debugger */
+ /* Returned from debugger, so reset kbd state. */
+ (void)SPLKD();
+ magic_state = KS_NORMAL;
+ if (kb_mode == KB_ASCII)
+ kd_state = KS_NORMAL;
+ /* setting leds kills kbd */
+ else {
+ kd_enqsc(K_ALTSC | K_UP);
+ kd_enqsc(K_CTLSC | K_UP);
+ kd_enqsc(K_dSC | K_UP);
+ }
+ return(TRUE);
+ break;
+#endif /* MACH_KDB */
+ case K_DELSC: /* ctl-alt-del */
+ /* if rebootflag is on, reboot the system */
+ if (rebootflag)
+ kdreboot();
+ break;
+ }
+ }
+ return(FALSE);
+}
+
+
+/*
+ * kdstate2idx:
+ *
+ * Return the value for the 2nd index into key_map that
+ * corresponds to the given state.
+ */
+unsigned int
+kdstate2idx(unsigned int state, /* bit vector, not a state index */
+ boolean_t extended)
+{
+ int state_idx = NORM_STATE;
+
+ if ((!extended) && state != KS_NORMAL) {
+ if ((state&(KS_SHIFTED|KS_ALTED)) == (KS_SHIFTED|KS_ALTED))
+ state_idx = SHIFT_ALT;
+ /* CTRL should have higher priority than SHIFT. That
+ way, CTRL-SHIFT-2 and CTRL-2 produce the same keycode.
+ --Derek Upham 1997/06/25 */
+ else if (state&KS_CTLED)
+ state_idx = CTRL_STATE;
+ else if (state&KS_SHIFTED)
+ state_idx = SHIFT_STATE;
+ else if (state&KS_ALTED)
+ state_idx = ALT_STATE;
+ }
+
+ return (CHARIDX(state_idx));
+}
+
+/*
+ * kdstart:
+ *
+ * This function does the general processing of characters and other
+ * operations for the device driver. The device independent portion of
+ * the tty driver calls this routine (it's setup in kdinit) with a
+ * given command. That command is then processed, and control is passed
+ * back to the kernel.
+ *
+ * input: tty pointer 'tp', and command to execute 'cmd'
+ *
+ * output: command is executed
+ *
+ * Entered and left at spltty. Drops priority to spl0 to display character.
+ * ASSUMES that it is never called from interrupt-driven code.
+ */
+void
+kdstart(struct tty *tp)
+{
+ spl_t o_pri;
+ int ch;
+
+ if (tp->t_state & TS_TTSTOP)
+ return;
+ for ( ; ; ) {
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_state & TS_TTSTOP)
+ break;
+ if ((tp->t_outq.c_cc <= 0) || (ch = getc(&tp->t_outq)) == -1)
+ break;
+ /*
+ * Drop priority for long screen updates. ttstart() calls us at
+ * spltty.
+ */
+ o_pri = splsoftclock(); /* block timeout */
+ kd_putc_esc(ch);
+ splx(o_pri);
+ }
+ if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
+ tt_write_wakeup(tp);
+ }
+}
+
+/*ARGSUSED*/
+void
+kdstop(
+ struct tty *tp,
+ int flags)
+{
+ /*
+ * do nothing - all characters are output by one call to
+ * kdstart.
+ */
+}
+
+/*
+ * kdinit:
+ *
+ * This code initializes the structures and sets up the port registers
+ * for the console driver.
+ *
+ * Each bitmap-based graphics card is likely to require a unique
+ * way to determine the card's presence. The driver runs through
+ * each "special" card that it knows about and uses the first one
+ * that it finds. If it doesn't find any, it assumes that an
+ * EGA-like card is installed.
+ *
+ * input : None. Interrupts are assumed to be disabled
+ * output : Driver is initialized
+ *
+ */
+void
+kdinit(void)
+{
+ unsigned char k_comm; /* keyboard command byte */
+
+ if (kd_initialized)
+ return;
+
+ esc_spt = esc_seq;
+ kd_attr = KA_NORMAL;
+
+ kd_attrflags = 0;
+ kd_color = KA_NORMAL;
+ /*
+ * board specific initialization: set up globals and kd_dxxx
+ * pointers, and synch displayed cursor with logical cursor.
+ */
+ kd_xga_init();
+
+ /* get rid of any garbage in output buffer */
+ if (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ kd_sendcmd(KC_CMD_READ); /* ask for the ctlr command byte */
+ k_comm = kd_getdata();
+ k_comm &= ~K_CB_DISBLE; /* clear keyboard disable bit */
+ k_comm |= K_CB_ENBLIRQ; /* enable interrupt */
+ kd_sendcmd(KC_CMD_WRITE); /* write new ctlr command byte */
+ kd_senddata(k_comm);
+ unmask_irq(KBD_IRQ);
+ kd_initialized = TRUE;
+
+#if ENABLE_IMMEDIATE_CONSOLE
+ /* Now that we're set up, we no longer need or want the
+ immediate console. */
+ {
+ extern boolean_t immediate_console_enable;
+ immediate_console_enable = FALSE;
+ }
+
+ /* The immediate console printed stuff at the bottom of the
+ screen rather than at the cursor position, so that's where
+ we should start. */
+ kd_setpos(ONE_PAGE - ONE_LINE); printf("\n");
+#endif /* ENABLE_IMMEDIATE_CONSOLE */
+
+ cnsetleds(kd_state = KS_NORMAL);
+ /* clear the LEDs AFTER we
+ enable the keyboard controller.
+ This keeps NUM-LOCK from being
+ set on the NEC Versa. */
+
+ /* Allocate the input buffer. */
+ ttychars(&kd_tty);
+}
+
+/*
+ * kd_belloff:
+ *
+ * This routine shuts the bell off, by sending the appropriate code
+ * to the speaker port.
+ *
+ * input : None
+ * output : bell is turned off
+ *
+ */
+static boolean_t kd_bellstate = FALSE;
+
+void
+kd_belloff(void * param)
+{
+ unsigned char status;
+
+ status = (inb(K_PORTB) & ~(K_SPKRDATA | K_ENABLETMR2));
+ outb(K_PORTB, status);
+ kd_bellstate = FALSE;
+ return;
+}
+
+
+/*
+ * kd_bellon:
+ *
+ * This routine turns the bell on.
+ *
+ * input : None
+ * output : bell is turned on
+ *
+ */
+void
+kd_bellon(void)
+{
+ unsigned char status;
+
+ /* program timer 2 */
+ outb(K_TMRCTL, K_SELTMR2 | K_RDLDTWORD | K_TSQRWAVE | K_TBINARY);
+ outb(K_TMR2, 1500 & 0xff); /* LSB */
+ outb(K_TMR2, (int)1500 >> 8); /* MSB */
+
+ /* start speaker - why must we turn on K_SPKRDATA? */
+ status = (inb(K_PORTB)| K_ENABLETMR2 | K_SPKRDATA);
+ outb(K_PORTB, status);
+ return;
+}
+
+/*
+ *
+ * Function kd_putc_esc():
+ *
+ * This function puts a character on the screen, handling escape
+ * sequences.
+ *
+ * input : character to be displayed (or part of an escape code)
+ * output : character is displayed, or some action is taken
+ *
+ */
+void
+kd_putc_esc(u_char c)
+{
+ if (c == (K_ESC)) {
+ if (esc_spt == esc_seq) {
+ *(esc_spt++)=(K_ESC);
+ *(esc_spt) = '\0';
+ } else {
+ kd_putc((K_ESC));
+ esc_spt = esc_seq;
+ }
+ } else {
+ if (esc_spt - esc_seq) {
+ if (esc_spt - esc_seq > K_MAXESC - 1)
+ esc_spt = esc_seq;
+ else {
+ *(esc_spt++) = c;
+ *(esc_spt) = '\0';
+ kd_parseesc();
+ }
+ } else {
+ kd_putc(c);
+ }
+ }
+}
+
+/*
+ *
+ * Function kd_putc():
+ *
+ * This function simply puts a character on the screen. It does some
+ * special processing for linefeed, carriage return, backspace and
+ * the bell.
+ *
+ * input : character to be displayed
+ * output : character is displayed, or some action is taken
+ *
+ */
+int sit_for_0 = 1;
+
+void
+kd_putc(u_char ch)
+{
+ if ((!ch) && sit_for_0)
+ return;
+
+ switch (ch) {
+ case ((K_LF)):
+ kd_down();
+ break;
+ case ((K_CR)):
+ kd_cr();
+ break;
+ case ((K_BS)):
+ kd_left();
+ break;
+ case ((K_HT)):
+ kd_tab();
+ break;
+ case ((K_BEL)):
+ /*
+ * Similar problem to K_BS here (behavior might depend
+ * on tty setting). Also check LF and CR.
+ */
+ if (!kd_bellstate)
+ {
+ kd_bellon();
+ timeout(kd_belloff, 0, hz/8 );
+ kd_bellstate = TRUE;
+ }
+ break;
+ default:
+ (*kd_dput)(kd_curpos, ch, kd_attr);
+ kd_right();
+ break;
+ }
+ return;
+}
+
+
+/*
+ * kd_setpos:
+ *
+ * This function sets the software and hardware cursor position
+ * on the screen, using device-specific code to actually move and
+ * display the cursor.
+ *
+ * input : position on (or off) screen to move the cursor to
+ * output : cursor position is updated, screen has been scrolled
+ * if necessary to bring cursor position back onto
+ * screen.
+ *
+ */
+void
+kd_setpos(csrpos_t newpos)
+{
+ if (newpos > ONE_PAGE) {
+ kd_scrollup();
+ newpos = BOTTOM_LINE;
+ }
+ if (newpos < 0) {
+ kd_scrolldn();
+ newpos = 0;
+ }
+
+ (*kd_dsetcursor)(newpos);
+}
+
+
+/*
+ * kd_scrollup:
+ *
+ * This function scrolls the screen up one line using a DMA memory
+ * copy.
+ *
+ * input : None
+ * output : lines on screen appear to be shifted up one line
+ *
+ */
+void
+kd_scrollup(void)
+{
+ csrpos_t to;
+ csrpos_t from;
+ int count;
+
+ /* scroll up */
+ to = 0;
+ from = ONE_LINE;
+ count = (ONE_PAGE - ONE_LINE)/ONE_SPACE;
+ (*kd_dmvup)(from, to, count);
+
+ /* clear bottom line */
+ to = BOTTOM_LINE;
+ count = ONE_LINE/ONE_SPACE;
+ (*kd_dclear)(to, count, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_scrolldn:
+ *
+ * Scrolls the characters on the screen down one line.
+ *
+ * input : None
+ * output : Lines on screen appear to be moved down one line
+ *
+ */
+void
+kd_scrolldn(void)
+{
+ csrpos_t to;
+ csrpos_t from;
+ int count;
+
+ /* move down */
+ to = ONE_PAGE - ONE_SPACE;
+ from = ONE_PAGE - ONE_LINE - ONE_SPACE;
+ count = (ONE_PAGE - ONE_LINE) / ONE_SPACE;
+ (*kd_dmvdown)(from, to, count);
+
+ /* clear top line */
+ to = 0;
+ count = ONE_LINE/ONE_SPACE;
+ (*kd_dclear)(to, count, kd_attr);
+ return;
+
+}
+
+
+/*
+ * kd_parseesc:
+ *
+ * This routine begins the parsing of an escape sequence. It uses the
+ * escape sequence array and the escape spot pointer to handle
+ * asynchronous parsing of escape sequences.
+ *
+ * input : String of characters prepended by an escape
+ * output : Appropriate actions are taken depending on the string as
+ * defined by the ansi terminal specification
+ *
+ */
+void
+kd_parseesc(void)
+{
+ u_char *escp;
+
+ escp = esc_seq + 1; /* point to char following ESC */
+ switch(*(escp)) {
+ case 'c':
+ kd_cls();
+ kd_home();
+ esc_spt = esc_seq; /* reset spot in ESC sequence */
+ break;
+ case '[':
+ escp++;
+ kd_parserest(escp);
+ break;
+ case '\0':
+ break; /* not enough info yet */
+ default:
+ kd_putc(*escp);
+ esc_spt = esc_seq; /* inv sequence char, reset */
+ break;
+ }
+ return;
+
+}
+
+
+/* kd_update_kd_attr:
+ *
+ * Updates kd_attr according to kd_attrflags and kd_color.
+ * This code has its origin from console.c and selection.h in
+ * linux 2.2 drivers/char/.
+ * Modified for GNU Mach by Marcus Brinkmann.
+ */
+
+#define reverse_video_char(a) (((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77))
+static void
+kd_update_kd_attr(void)
+{
+ kd_attr = kd_color;
+ if (kd_attrflags & KAX_UNDERLINE)
+ kd_attr = (kd_attr & 0xf0) | KAX_COL_UNDERLINE;
+ else if (kd_attrflags & KAX_DIM)
+ kd_attr = (kd_attr & 0xf0) | KAX_COL_DIM;
+ if (kd_attrflags & KAX_REVERSE)
+ kd_attr = reverse_video_char(kd_attr);
+ if (kd_attrflags & KAX_BLINK)
+ kd_attr ^= 0x80;
+ if (kd_attrflags & KAX_BOLD)
+ kd_attr ^= 0x08;
+}
+
+/* color_table added by Julio Merino to take proper color order.
+ * I get this code from Linux 2.2 source code in file:
+ * linux/drivers/char/console.c
+ */
+unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+ 8,12,10,14, 9,13,11,15 };
+/*
+ * kd_parserest:
+ *
+ * This function will complete the parsing of an escape sequence and
+ * call the appropriate support routine if it matches a character. This
+ * function could be greatly improved by using a function jump table, and
+ * removing this bulky switch statement.
+ *
+ * input : An string
+ * output : Appropriate action based on whether the string matches a
+ * sequence acceptable to the ansi terminal specification
+ *
+ */
+void
+kd_parserest(u_char *cp)
+{
+ int number[16], npar = 0, i;
+ csrpos_t newpos;
+
+ for(i=0;i<=15;i++)
+ number[i] = MACH_ATOI_DEFAULT;
+
+ do {
+ cp += mach_atoi(cp, &number[npar]);
+ } while (*cp == ';' && ++npar <= 15 && cp++);
+
+ switch(*cp) {
+ case 'm':
+ for (i=0;i<=npar;i++)
+ switch(number[i]) {
+ case MACH_ATOI_DEFAULT:
+ case 0:
+ kd_attrflags = 0;
+ kd_color = KA_NORMAL;
+ break;
+ case 1:
+ kd_attrflags |= KAX_BOLD;
+ kd_attrflags &= ~KAX_DIM;
+ break;
+ case 2:
+ kd_attrflags |= KAX_DIM;
+ kd_attrflags &= ~KAX_BOLD;
+ break;
+ case 4:
+ kd_attrflags |= KAX_UNDERLINE;
+ break;
+ case 5:
+ kd_attrflags |= KAX_BLINK;
+ break;
+ case 7:
+ kd_attrflags |= KAX_REVERSE;
+ break;
+ case 8:
+ kd_attrflags |= KAX_INVISIBLE;
+ break;
+ case 21:
+ case 22:
+ kd_attrflags &= ~(KAX_BOLD | KAX_DIM);
+ break;
+ case 24:
+ kd_attrflags &= ~KAX_UNDERLINE;
+ break;
+ case 25:
+ kd_attrflags &= ~KAX_BLINK;
+ break;
+ case 27:
+ kd_attrflags &= ~KAX_REVERSE;
+ break;
+ case 38:
+ kd_attrflags |= KAX_UNDERLINE;
+ kd_color = (kd_color & 0xf0) | (KA_NORMAL & 0x0f);
+ break;
+ case 39:
+ kd_attrflags &= ~KAX_UNDERLINE;
+ kd_color = (kd_color & 0xf0) | (KA_NORMAL & 0x0f);
+ break;
+ default:
+ if (number[i] >= 30 && number[i] <= 37) {
+ /* foreground color */
+ kd_color = (kd_color & 0xf0) | color_table[(number[i] - 30)];
+ } else if (number[i] >= 40 && number[i] <= 47) {
+ /* background color */
+ kd_color = (kd_color & 0x0f) | (color_table[(number[i] - 40)] << 4);
+ }
+ break;
+ }
+ kd_update_kd_attr();
+ esc_spt = esc_seq;
+ break;
+ case '@':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_insch(1);
+ else
+ kd_insch(number[0]);
+ esc_spt = esc_seq;
+ break;
+ case 'A':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_up();
+ else
+ while (number[0]--)
+ kd_up();
+ esc_spt = esc_seq;
+ break;
+ case 'B':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_down();
+ else
+ while (number[0]--)
+ kd_down();
+ esc_spt = esc_seq;
+ break;
+ case 'C':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_right();
+ else
+ while (number[0]--)
+ kd_right();
+ esc_spt = esc_seq;
+ break;
+ case 'D':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_left();
+ else
+ while (number[0]--)
+ kd_left();
+ esc_spt = esc_seq;
+ break;
+ case 'E':
+ kd_cr();
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_down();
+ else
+ while (number[0]--)
+ kd_down();
+ esc_spt = esc_seq;
+ break;
+ case 'F':
+ kd_cr();
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_up();
+ else
+ while (number[0]--)
+ kd_up();
+ esc_spt = esc_seq;
+ break;
+ case 'G':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ number[0] = 0;
+ else
+ if (number[0] > 0)
+ --number[0]; /* because number[0] is from 1 */
+ kd_setpos(BEG_OF_LINE(kd_curpos) + number[0] * ONE_SPACE);
+ esc_spt = esc_seq;
+ break;
+ case 'f':
+ case 'H':
+ if (number[0] == MACH_ATOI_DEFAULT && number[1] == MACH_ATOI_DEFAULT)
+ {
+ kd_home();
+ esc_spt = esc_seq;
+ break;
+ }
+ if (number[0] == MACH_ATOI_DEFAULT)
+ number[0] = 0;
+ else if (number[0] > 0)
+ --number[0]; /* numbered from 1 */
+ newpos = (number[0] * ONE_LINE); /* setup row */
+ if (number[1] == MACH_ATOI_DEFAULT)
+ number[1] = 0;
+ else if (number[1] > 0)
+ number[1]--;
+ newpos += (number[1] * ONE_SPACE); /* setup column */
+ if (newpos < 0)
+ newpos = 0; /* upper left */
+ if (newpos > ONE_PAGE)
+ newpos = (ONE_PAGE - ONE_SPACE); /* lower right */
+ kd_setpos(newpos);
+ esc_spt = esc_seq;
+ break; /* done or not ready */
+ case 'J':
+ switch(number[0]) {
+ case MACH_ATOI_DEFAULT:
+ case 0:
+ kd_cltobcur(); /* clears from current
+ pos to bottom.
+ */
+ break;
+ case 1:
+ kd_cltopcur(); /* clears from top to
+ current pos.
+ */
+ break;
+ case 2:
+ kd_cls();
+ break;
+ default:
+ break;
+ }
+ esc_spt = esc_seq; /* reset it */
+ break;
+ case 'K':
+ switch(number[0]) {
+ case MACH_ATOI_DEFAULT:
+ case 0:
+ kd_cltoecur(); /* clears from current
+ pos to eoln.
+ */
+ break;
+ case 1:
+ kd_clfrbcur(); /* clears from begin
+ of line to current
+ pos.
+ */
+ break;
+ case 2:
+ kd_eraseln(); /* clear entire line */
+ break;
+ default:
+ break;
+ }
+ esc_spt = esc_seq;
+ break;
+ case 'L':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_insln(1);
+ else
+ kd_insln(number[0]);
+ esc_spt = esc_seq;
+ break;
+ case 'M':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_delln(1);
+ else
+ kd_delln(number[0]);
+ esc_spt = esc_seq;
+ break;
+ case 'P':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_delch(1);
+ else
+ kd_delch(number[0]);
+ esc_spt = esc_seq;
+ break;
+ case 'S':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_scrollup();
+ else
+ while (number[0]--)
+ kd_scrollup();
+ esc_spt = esc_seq;
+ break;
+ case 'T':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_scrolldn();
+ else
+ while (number[0]--)
+ kd_scrolldn();
+ esc_spt = esc_seq;
+ break;
+ case 'X':
+ if (number[0] == MACH_ATOI_DEFAULT)
+ kd_erase(1);
+ else
+ kd_erase(number[0]);
+ esc_spt = esc_seq;
+ break;
+ case '\0':
+ break; /* not enough yet */
+ default:
+ kd_putc(*cp); /* show inv character */
+ esc_spt = esc_seq; /* inv entry, reset */
+ break;
+ }
+ return;
+}
+
+void
+kd_tab(void)
+{
+ int i;
+
+ for (i = 8 - (CURRENT_COLUMN(kd_curpos) % 8); i > 0; i--) {
+ kd_putc(' ');
+ }
+
+}
+
+
+/*
+ * kd_cls:
+ *
+ * This function clears the screen with spaces and the current attribute.
+ *
+ * input : None
+ * output : Screen is cleared
+ *
+ */
+void
+kd_cls(void)
+{
+ (*kd_dclear)(0, ONE_PAGE/ONE_SPACE, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_home:
+ *
+ * This function will move the cursor to the home position on the screen,
+ * as well as set the internal cursor position (kd_curpos) to home.
+ *
+ * input : None
+ * output : Cursor position is moved
+ *
+ */
+void
+kd_home(void)
+{
+ kd_setpos(0);
+ return;
+}
+
+
+/*
+ * kd_up:
+ *
+ * This function moves the cursor up one line position.
+ *
+ * input : None
+ * output : Cursor moves up one line, or screen is scrolled
+ *
+ */
+void
+kd_up(void)
+{
+ if (kd_curpos < ONE_LINE)
+ kd_scrolldn();
+ else
+ kd_setpos(kd_curpos - ONE_LINE);
+ return;
+}
+
+
+/*
+ * kd_down:
+ *
+ * This function moves the cursor down one line position.
+ *
+ * input : None
+ * output : Cursor moves down one line or the screen is scrolled
+ *
+ */
+void
+kd_down(void)
+{
+ if (kd_curpos >= (ONE_PAGE - ONE_LINE))
+ kd_scrollup();
+ else
+ kd_setpos(kd_curpos + ONE_LINE);
+ return;
+}
+
+
+/*
+ * kd_right:
+ *
+ * This function moves the cursor one position to the right.
+ *
+ * input : None
+ * output : Cursor moves one position to the right
+ *
+ */
+void
+kd_right(void)
+{
+ if (kd_curpos < (ONE_PAGE - ONE_SPACE))
+ kd_setpos(kd_curpos + ONE_SPACE);
+ else {
+ kd_scrollup();
+ kd_setpos(BEG_OF_LINE(kd_curpos));
+ }
+ return;
+}
+
+
+/*
+ * kd_left:
+ *
+ * This function moves the cursor one position to the left.
+ *
+ * input : None
+ * output : Cursor moves one position to the left
+ *
+ */
+void
+kd_left(void)
+{
+ if (0 < kd_curpos)
+ kd_setpos(kd_curpos - ONE_SPACE);
+ return;
+}
+
+
+/*
+ * kd_cr:
+ *
+ * This function moves the cursor to the beginning of the current
+ * line.
+ *
+ * input : None
+ * output : Cursor moves to the beginning of the current line
+ *
+ */
+void
+kd_cr(void)
+{
+ kd_setpos(BEG_OF_LINE(kd_curpos));
+ return;
+}
+
+
+/*
+ * kd_cltobcur:
+ *
+ * This function clears from the current cursor position to the bottom
+ * of the screen.
+ *
+ * input : None
+ * output : Screen is cleared from current cursor position to bottom
+ *
+ */
+void
+kd_cltobcur(void)
+{
+ csrpos_t start;
+ int count;
+
+ start = kd_curpos;
+ count = (ONE_PAGE - kd_curpos)/ONE_SPACE;
+ (*kd_dclear)(start, count, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_cltopcur:
+ *
+ * This function clears from the current cursor position to the top
+ * of the screen.
+ *
+ * input : None
+ * output : Screen is cleared from current cursor position to top
+ *
+ */
+void
+kd_cltopcur(void)
+{
+ int count;
+
+ count = (kd_curpos + ONE_SPACE) / ONE_SPACE;
+ (*kd_dclear)(0, count, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_cltoecur:
+ *
+ * This function clears from the current cursor position to eoln.
+ *
+ * input : None
+ * output : Line is cleared from current cursor position to eoln
+ *
+ */
+void
+kd_cltoecur(void)
+{
+ csrpos_t i;
+ csrpos_t hold;
+
+ hold = BEG_OF_LINE(kd_curpos) + ONE_LINE;
+ for (i = kd_curpos; i < hold; i += ONE_SPACE) {
+ (*kd_dput)(i, K_SPACE, kd_attr);
+ }
+}
+
+
+/*
+ * kd_clfrbcur:
+ *
+ * This function clears from the beginning of the line to the current
+ * cursor position.
+ *
+ * input : None
+ * output : Line is cleared from beginning to current position
+ *
+ */
+void
+kd_clfrbcur(void)
+{
+ csrpos_t i;
+
+ for (i = BEG_OF_LINE(kd_curpos); i <= kd_curpos; i += ONE_SPACE) {
+ (*kd_dput)(i, K_SPACE, kd_attr);
+ }
+}
+
+
+/*
+ * kd_delln:
+ *
+ * This function deletes 'number' lines on the screen by effectively
+ * scrolling the lines up and replacing the old lines with spaces.
+ *
+ * input : number of lines to delete
+ * output : lines appear to be deleted
+ *
+ */
+void
+kd_delln(int number)
+{
+ csrpos_t to;
+ csrpos_t from;
+ int delbytes; /* num of bytes to delete */
+ int count; /* num of words to move or fill */
+
+ if (number <= 0)
+ return;
+
+ delbytes = number * ONE_LINE;
+ to = BEG_OF_LINE(kd_curpos);
+ if (to + delbytes >= ONE_PAGE)
+ delbytes = ONE_PAGE - to;
+ if (to + delbytes < ONE_PAGE) {
+ from = to + delbytes;
+ count = (ONE_PAGE - from) / ONE_SPACE;
+ (*kd_dmvup)(from, to, count);
+ }
+
+ to = ONE_PAGE - delbytes;
+ count = delbytes / ONE_SPACE;
+ (*kd_dclear)(to, count, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_insln:
+ *
+ * This function inserts a line above the current one by
+ * scrolling the current line and all the lines below it down.
+ *
+ * input : number of lines to insert
+ * output : New lines appear to be inserted
+ *
+ */
+void
+kd_insln(int number)
+{
+ csrpos_t to;
+ csrpos_t from;
+ int count;
+ csrpos_t top; /* top of block to be moved */
+ int insbytes; /* num of bytes inserted */
+
+ if (number <= 0)
+ return;
+
+ top = BEG_OF_LINE(kd_curpos);
+ insbytes = number * ONE_LINE;
+ if (top + insbytes > ONE_PAGE)
+ insbytes = ONE_PAGE - top;
+ to = ONE_PAGE - ONE_SPACE;
+ from = to - insbytes;
+ if (from > top) {
+ count = (from - top + ONE_SPACE) / ONE_SPACE;
+ (*kd_dmvdown)(from, to, count);
+ }
+
+ count = insbytes / ONE_SPACE;
+ (*kd_dclear)(top, count, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_delch:
+ *
+ * This function deletes a number of characters from the current
+ * position in the line.
+ *
+ * input : number of characters to delete
+ * output : characters appear to be deleted
+ *
+ */
+void
+kd_delch(int number)
+{
+ int count; /* num words moved/filled */
+ int delbytes; /* bytes to delete */
+ csrpos_t to;
+ csrpos_t from;
+ csrpos_t nextline; /* start of next line */
+
+ if (number <= 0)
+ return;
+
+ nextline = BEG_OF_LINE(kd_curpos) + ONE_LINE;
+ delbytes = number * ONE_SPACE;
+ if (kd_curpos + delbytes > nextline)
+ delbytes = nextline - kd_curpos;
+ if (kd_curpos + delbytes < nextline) {
+ from = kd_curpos + delbytes;
+ to = kd_curpos;
+ count = (nextline - from) / ONE_SPACE;
+ (*kd_dmvup)(from, to, count);
+ }
+
+ to = nextline - delbytes;
+ count = delbytes / ONE_SPACE;
+ (*kd_dclear)(to, count, kd_attr);
+ return;
+
+}
+
+
+/*
+ * kd_erase:
+ *
+ * This function overwrites characters with a space starting with the
+ * current cursor position and ending in number spaces away.
+ *
+ * input : number of characters to erase
+ * output : characters appear to be blanked or erased
+ *
+ */
+void
+kd_erase(int number)
+{
+ csrpos_t i;
+ csrpos_t stop;
+
+ stop = kd_curpos + (ONE_SPACE * number);
+ if (stop > BEG_OF_LINE(kd_curpos) + ONE_LINE)
+ stop = BEG_OF_LINE(kd_curpos) + ONE_LINE;
+ for (i = kd_curpos; i < stop; i += ONE_SPACE) {
+ (*kd_dput)(i, K_SPACE, kd_attr);
+ }
+ return;
+}
+
+
+/*
+ * kd_eraseln:
+ *
+ * This function erases the current line with spaces.
+ *
+ * input : None
+ * output : Current line is erased
+ *
+ */
+void
+kd_eraseln(void)
+{
+ csrpos_t i;
+ csrpos_t stop;
+
+ stop = BEG_OF_LINE(kd_curpos) + ONE_LINE;
+ for (i = BEG_OF_LINE(kd_curpos); i < stop; i += ONE_SPACE) {
+ (*kd_dput)(i, K_SPACE, kd_attr);
+ }
+ return;
+}
+
+
+/*
+ * kd_insch:
+ *
+ * This function inserts a blank at the current cursor position
+ * and moves all other characters on the line over.
+ *
+ * input : number of blanks to insert
+ * output : Blanks are inserted at cursor position
+ *
+ */
+void
+kd_insch(int number)
+{
+ csrpos_t to;
+ csrpos_t from;
+ int count;
+ csrpos_t nextline; /* start of next line */
+ int insbytes; /* num of bytes inserted */
+
+ if (number <= 0)
+ return;
+
+ nextline = BEG_OF_LINE(kd_curpos) + ONE_LINE;
+ insbytes = number * ONE_SPACE;
+ if (kd_curpos + insbytes > nextline)
+ insbytes = nextline - kd_curpos;
+
+ to = nextline - ONE_SPACE;
+ from = to - insbytes;
+ if (from >= kd_curpos) {
+ count = (from - kd_curpos + ONE_SPACE) / ONE_SPACE;
+ (*kd_dmvdown)(from, to, count);
+ }
+
+ count = insbytes / ONE_SPACE;
+ (*kd_dclear)(kd_curpos, count, kd_attr);
+ return;
+}
+
+
+/*
+ * kd_isupper, kd_islower:
+ *
+ * Didn't want to include ctype.h because it brings in stdio.h, and
+ * only want to see if the darn character is uppercase or lowercase.
+ *
+ * input : Character 'c'
+ * output : isuuper gives TRUE if character is uppercase, islower
+ * returns TRUE if character is lowercase
+ *
+ */
+boolean_t
+kd_isupper(u_char c)
+{
+ if (('A' <= c) && (c <= 'Z'))
+ return(TRUE);
+ return(FALSE);
+}
+
+boolean_t
+kd_islower(u_char c)
+{
+ if (('a' <= c) && (c <= 'z'))
+ return(TRUE);
+ return(FALSE);
+}
+
+/*
+ * kd_senddata:
+ *
+ * This function sends a byte to the keyboard RDWR port, but
+ * first waits until the input/output data buffer is clear before
+ * sending the data. Note that this byte can be either data or a
+ * keyboard command.
+ *
+ */
+void
+kd_senddata(unsigned char ch)
+{
+ while (inb(K_STATUS) & K_IBUF_FUL)
+ ;
+ outb(K_RDWR, ch);
+ last_sent = ch;
+ return;
+}
+
+/*
+ * kd_sendcmd:
+ *
+ * This function sends a command byte to the keyboard command
+ * port, but first waits until the input/output data buffer is
+ * clear before sending the data.
+ *
+ */
+void
+kd_sendcmd(unsigned char ch)
+{
+ while (inb(K_STATUS) & K_IBUF_FUL)
+ ;
+ outb(K_CMD, ch);
+ return;
+}
+
+
+/*
+ * kd_getdata:
+ *
+ * This function returns a data byte from the keyboard RDWR port,
+ * after waiting until the port is flagged as having something to
+ * read.
+ */
+unsigned char
+kd_getdata(void)
+{
+ while ((inb(K_STATUS) & K_OBUF_FUL) == 0)
+ ;
+ return(inb(K_RDWR));
+}
+
+void
+kd_cmdreg_write(int val)
+{
+int ch=KC_CMD_WRITE;
+
+ while (inb(K_STATUS) & K_IBUF_FUL)
+ ;
+ outb(K_CMD, ch);
+
+ while (inb(K_STATUS) & K_IBUF_FUL)
+ ;
+ outb(K_RDWR, val);
+}
+
+void
+kd_mouse_drain(void)
+{
+ int i;
+ while(inb(K_STATUS) & K_IBUF_FUL)
+ ;
+ while((i = inb(K_STATUS)) & K_OBUF_FUL)
+ printf("kbd: S = %x D = %x\n", i, inb(K_RDWR));
+}
+
+/*
+ * set_kd_state:
+ *
+ * Set kd_state and update the keyboard status LEDs.
+ */
+void
+set_kd_state(int newstate)
+{
+ kd_state = newstate;
+ kd_setleds1(state2leds(newstate));
+}
+
+/*
+ * state2leds:
+ *
+ * Return a byte containing LED settings for the keyboard, given
+ * a state vector.
+ */
+u_char
+state2leds(int state)
+{
+ u_char result = 0;
+
+ if (state & KS_NLKED)
+ result |= K_LED_NUMLK;
+ if (state & KS_CLKED)
+ result |= K_LED_CAPSLK;
+ return(result);
+}
+
+/*
+ * kd_setleds[12]:
+ *
+ * Set the keyboard LEDs according to the given byte.
+ */
+void
+kd_setleds1(u_char val)
+{
+ if (kd_ack != NOT_WAITING) {
+#ifdef MACH_KBD
+ printf("kd_setleds1: unexpected state (%d)\n", kd_ack);
+#endif
+ return;
+ }
+
+ kd_ack = SET_LEDS;
+ kd_nextled = val;
+ kd_senddata(K_CMD_LEDS);
+}
+
+void
+kd_setleds2(void)
+{
+ kd_senddata(kd_nextled);
+}
+
+
+/*
+ * cnsetleds:
+ *
+ * like kd_setleds[12], but not interrupt-based.
+ * Currently disabled because cngetc ignores caps lock and num
+ * lock anyway.
+ */
+void
+cnsetleds(u_char val)
+{
+ kd_senddata(K_CMD_LEDS);
+ (void)kd_getdata(); /* XXX - assume is ACK */
+ kd_senddata(val);
+ (void)kd_getdata(); /* XXX - assume is ACK */
+}
+
+void
+kdreboot(void)
+{
+ (*kd_dreset)();
+
+#ifndef BROKEN_KEYBOARD_RESET
+ kd_sendcmd(0xFE); /* XXX - magic # */
+ delay(1000000); /* wait to see if anything happens */
+#endif
+ /*
+ * If that didn't work, then we'll just have to try and
+ * do it the hard way.
+ */
+ cpu_shutdown();
+}
+
+static int which_button[] = {0, MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT};
+static struct mouse_motion moved;
+
+int
+kd_kbd_magic(int scancode)
+{
+int new_button = 0;
+
+ if (kd_kbd_mouse == 2)
+ printf("sc = %x\n", scancode);
+
+ switch (scancode) {
+/* f1 f2 f3 */
+ case 0x3d:
+ new_button++;
+ case 0x3c:
+ new_button++;
+ case 0x3b:
+ new_button++;
+ if (kd_kbd_magic_button && (new_button != kd_kbd_magic_button)) {
+ /* down w/o up */
+ mouse_button(which_button[kd_kbd_magic_button], 1);
+ }
+ /* normal */
+ if (kd_kbd_magic_button == new_button) {
+ mouse_button(which_button[new_button], 1);
+ kd_kbd_magic_button = 0;
+ } else {
+ mouse_button(which_button[new_button], 0);
+ kd_kbd_magic_button = new_button;
+ }
+ break;
+
+/* right left up down */
+ case 0x4d:
+ moved.mm_deltaX = kd_kbd_magic_scale;
+ moved.mm_deltaY = 0;
+ mouse_moved(moved);
+ break;
+ case 0x4b:
+ moved.mm_deltaX = -kd_kbd_magic_scale;
+ moved.mm_deltaY = 0;
+ mouse_moved(moved);
+ break;
+ case 0x48:
+ moved.mm_deltaX = 0;
+ moved.mm_deltaY = kd_kbd_magic_scale;
+ mouse_moved(moved);
+ break;
+ case 0x50:
+ moved.mm_deltaX = 0;
+ moved.mm_deltaY = -kd_kbd_magic_scale;
+ mouse_moved(moved);
+ break;
+/* home pageup end pagedown */
+ case 0x47:
+ moved.mm_deltaX = -2*kd_kbd_magic_scale;
+ moved.mm_deltaY = 2*kd_kbd_magic_scale;
+ mouse_moved(moved);
+ break;
+ case 0x49:
+ moved.mm_deltaX = 2*kd_kbd_magic_scale;
+ moved.mm_deltaY = 2*kd_kbd_magic_scale;
+ mouse_moved(moved);
+ break;
+ case 0x4f:
+ moved.mm_deltaX = -2*kd_kbd_magic_scale;
+ moved.mm_deltaY = -2*kd_kbd_magic_scale;
+ mouse_moved(moved);
+ break;
+ case 0x51:
+ moved.mm_deltaX = 2*kd_kbd_magic_scale;
+ moved.mm_deltaY = -2*kd_kbd_magic_scale;
+ mouse_moved(moved);
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+
+/*
+ * Code specific to EGA/CGA/VGA boards. This code relies on the fact
+ * that the "slam" functions take a word count and ONE_SPACE takes up
+ * 1 word.
+ */
+#define SLAMBPW 2 /* bytes per word for "slam" fcns */
+
+/*
+ * xga_getpos:
+ *
+ * This function returns the current hardware cursor position on the
+ * screen, scaled for compatibility with kd_curpos.
+ *
+ * input : None
+ * output : returns the value of cursor position on screen
+ *
+ */
+static csrpos_t
+xga_getpos(void)
+
+{
+ unsigned char low;
+ unsigned char high;
+ short pos;
+
+ outb(kd_index_reg, C_HIGH);
+ high = inb(kd_io_reg);
+ outb(kd_index_reg, C_LOW);
+ low = inb(kd_io_reg);
+ pos = (0xff&low) + ((unsigned short)high<<8);
+
+ return(ONE_SPACE * (csrpos_t)pos);
+}
+
+
+/*
+ * kd_xga_init:
+ *
+ * Initialization specific to character-based graphics adapters.
+ */
+void
+kd_xga_init(void)
+{
+ unsigned char start, stop;
+
+#if 0
+ unsigned char screen;
+
+ /* XXX: this conflicts with read/writing the RTC */
+
+ outb(CMOS_ADDR, CMOS_EB);
+ screen = inb(CMOS_DATA) & CM_SCRMSK;
+ switch(screen) {
+ default:
+ printf("kd: unknown screen type, defaulting to EGA\n");
+ /* FALLTHROUGH */
+ case CM_EGA_VGA:
+#endif
+ /*
+ * Here we'll want to query to bios on the card
+ * itself, because then we can figure out what
+ * type we have exactly. At this point we only
+ * know that the card is NOT CGA or MONO. For
+ * now, however, we assume backwards compatibility
+ * with 0xb8000 as the starting screen offset
+ * memory location for these cards.
+ *
+ */
+
+ vid_start = (u_char *)phystokv(EGA_START);
+ kd_index_reg = EGA_IDX_REG;
+ kd_io_reg = EGA_IO_REG;
+ kd_lines = 25;
+ kd_cols = 80;
+ kd_bitmap_start = 0xa0000; /* XXX - magic numbers */
+ { /* XXX - is there a cleaner way to do this? */
+ char *addr = (char *)phystokv(kd_bitmap_start);
+ int i;
+ for (i = 0; i < 200; i++)
+ addr[i] = 0x00;
+ }
+#if 0
+ break;
+ /* XXX: some buggy BIOSes report these... */
+ case CM_CGA_40:
+ vid_start = (u_char *)phystokv(CGA_START);
+ kd_index_reg = CGA_IDX_REG;
+ kd_io_reg = CGA_IO_REG;
+ kd_lines = 25;
+ kd_cols = 40;
+ break;
+ case CM_CGA_80:
+ vid_start = (u_char *)phystokv(CGA_START);
+ kd_index_reg = CGA_IDX_REG;
+ kd_io_reg = CGA_IO_REG;
+ kd_lines = 25;
+ kd_cols = 80;
+ break;
+ case CM_MONO_80:
+ vid_start = (u_char *)phystokv(MONO_START);
+ kd_index_reg = MONO_IDX_REG;
+ kd_io_reg = MONO_IO_REG;
+ kd_lines = 25;
+ kd_cols = 80;
+ break;
+ }
+#endif
+
+ outb(kd_index_reg, C_START);
+ start = inb(kd_io_reg);
+ /* Make sure cursor is enabled */
+ start &= ~0x20;
+ outb(kd_io_reg, start);
+ outb(kd_index_reg, C_STOP);
+ stop = inb(kd_io_reg);
+
+ if (!start && !stop)
+ {
+ /* Some firmware seem not to be initializing the cursor size
+ * any more... Try using standard values. */
+ outb(kd_index_reg, C_START);
+ outb(kd_io_reg, 14);
+ outb(kd_index_reg, C_STOP);
+ outb(kd_io_reg, 15);
+ }
+
+ kd_setpos(xga_getpos());
+}
+
+
+/*
+ * charput:
+ *
+ * Put attributed character for EGA/CGA/etc.
+ */
+static void
+charput(csrpos_t pos, char ch, char chattr)
+{
+ *(vid_start + pos) = ch;
+ *(vid_start + pos + 1) = chattr;
+}
+
+
+/*
+ * charsetcursor:
+ *
+ * Set hardware cursor position for EGA/CGA/etc.
+ */
+static void
+charsetcursor(csrpos_t newpos)
+{
+ short curpos; /* position, not scaled for attribute byte */
+
+ curpos = newpos / ONE_SPACE;
+ outb(kd_index_reg, C_HIGH);
+ outb(kd_io_reg, (u_char)(curpos>>8));
+ outb(kd_index_reg, C_LOW);
+ outb(kd_io_reg, (u_char)(curpos&0xff));
+
+ kd_curpos = newpos;
+}
+
+
+/*
+ * charmvup:
+ *
+ * Block move up for EGA/CGA/etc.
+ */
+static void
+charmvup(csrpos_t from, csrpos_t to, int count)
+{
+ kd_slmscu(vid_start+from, vid_start+to, count);
+}
+
+
+/*
+ * charmvdown:
+ *
+ * Block move down for EGA/CGA/etc.
+ */
+static void
+charmvdown(csrpos_t from, csrpos_t to, int count)
+{
+ kd_slmscd(vid_start+from, vid_start+to, count);
+}
+
+
+/*
+ * charclear:
+ *
+ * Fast clear for CGA/EGA/etc.
+ */
+static void
+charclear(csrpos_t to, int count, char chattr)
+{
+ kd_slmwd(vid_start+to, count, ((unsigned short)chattr<<8)+K_SPACE);
+}
+
+
+/*
+ * kd_noopreset:
+ *
+ * No-op reset routine for kd_dreset.
+ */
+static void
+kd_noopreset(void)
+{
+}
+
+
+/*
+ * bmpput: Copy a character from the font to the frame buffer.
+ */
+
+void
+bmpput(
+ csrpos_t pos,
+ char ch,
+ char chattr)
+{
+ short xbit, ybit; /* u/l corner of char pos */
+ u_char *to, *from;
+ short i, j;
+ u_char mask = (chattr == KA_REVERSE ? 0xff : 0);
+
+ if ((u_char)ch >= chars_in_font)
+ ch = K_QUES;
+
+ bmpch2bit(pos, &xbit, &ybit);
+ to = bit2fbptr(xbit, ybit);
+ from = font_start + ch * char_byte_width;
+ for (i = 0; i < char_height; ++i) {
+ for (j = 0; j < char_byte_width; ++j)
+ *(to+j) = *(from+j) ^ mask;
+ to += fb_byte_width;
+ from += font_byte_width;
+ }
+}
+
+/*
+ * bmpcp1char: copy 1 char from one place in the frame buffer to
+ * another.
+ */
+static void
+bmpcp1char(
+ csrpos_t from,
+ csrpos_t to)
+{
+ short from_xbit, from_ybit;
+ short to_xbit, to_ybit;
+ u_char *tp, *fp;
+ short i, j;
+
+ bmpch2bit(from, &from_xbit, &from_ybit);
+ bmpch2bit(to, &to_xbit, &to_ybit);
+
+ tp = bit2fbptr(to_xbit, to_ybit);
+ fp = bit2fbptr(from_xbit, from_ybit);
+
+ for (i = 0; i < char_height; ++i) {
+ for (j = 0; j < char_byte_width; ++j)
+ *(tp+j) = *(fp+j);
+ tp += fb_byte_width;
+ fp += fb_byte_width;
+ }
+}
+
+/*
+ * bmpvmup: Copy a block of character positions upwards.
+ */
+void
+bmpmvup(
+ csrpos_t from,
+ csrpos_t to,
+ int count)
+{
+ short from_xbit, from_ybit;
+ short to_xbit, to_ybit;
+ short i;
+
+ bmpch2bit(from, &from_xbit, &from_ybit);
+ bmpch2bit(to, &to_xbit, &to_ybit);
+
+ if (from_xbit == xstart && to_xbit == xstart && count%kd_cols == 0) {
+ /* fast case - entire lines */
+ from_xbit = to_xbit = 0;
+ bmppaintcsr(kd_curpos, char_black); /* don't copy cursor */
+ count /= kd_cols; /* num lines */
+ count *= fb_byte_width * (char_height+cursor_height);
+ kd_slmscu(bit2fbptr(from_xbit, from_ybit),
+ bit2fbptr(to_xbit, to_ybit),
+ count/SLAMBPW);
+ bmppaintcsr(kd_curpos, char_white);
+ } else {
+ /* slow case - everything else */
+ for (i=0; i < count; ++i) {
+ bmpcp1char(from, to);
+ from += ONE_SPACE;
+ to += ONE_SPACE;
+ }
+ }
+}
+
+/*
+ * bmpmvdown: copy a block of characters down.
+ */
+void
+bmpmvdown(
+ csrpos_t from,
+ csrpos_t to,
+ int count)
+{
+ short from_xbit, from_ybit;
+ short to_xbit, to_ybit;
+ short i;
+
+ bmpch2bit(from, &from_xbit, &from_ybit);
+ bmpch2bit(to, &to_xbit, &to_ybit);
+
+ if (from_xbit == xstart + (kd_cols - 1) * char_width
+ && to_xbit == xstart + (kd_cols - 1) * char_width
+ && count%kd_cols == 0) {
+ /* fast case - entire lines*/
+ from_xbit = to_xbit = 8 * (fb_byte_width - 1);
+ /* last byte on line */
+ bmppaintcsr(kd_curpos, char_black); /* don't copy cursor */
+ count /= kd_cols; /* num lines */
+ count *= fb_byte_width * (char_height+cursor_height);
+ kd_slmscd(bit2fbptr(from_xbit, from_ybit),
+ bit2fbptr(to_xbit, to_ybit),
+ count/SLAMBPW);
+ bmppaintcsr(kd_curpos, char_white);
+ } else {
+ /* slow case - everything else */
+ for (i=0; i < count; ++i) {
+ bmpcp1char(from, to);
+ from -= ONE_SPACE;
+ to -= ONE_SPACE;
+ }
+ }
+}
+
+/*
+ * bmpclear: clear one or more character positions.
+ */
+void
+bmpclear(
+ csrpos_t to, /* 1st char */
+ int count, /* num chars */
+ char chattr) /* reverse or normal */
+{
+ short i;
+ u_short clearval;
+ u_short clearbyte = (chattr == KA_REVERSE ? char_white : char_black);
+
+ clearval = (u_short)(clearbyte<<8) + clearbyte;
+ if (to == 0 && count >= kd_lines * kd_cols) {
+ /* fast case - entire page */
+ kd_slmwd(vid_start, (fb_byte_width * fb_height)/SLAMBPW,
+ clearval);
+ } else
+ /* slow case */
+ for (i = 0; i < count; ++i) {
+ bmpput(to, K_SPACE, chattr);
+ to += ONE_SPACE;
+ }
+}
+
+/*
+ * bmpsetcursor: update the display and set the logical cursor.
+ */
+void
+bmpsetcursor(csrpos_t pos)
+{
+ /* erase old cursor & paint new one */
+ bmppaintcsr(kd_curpos, char_black);
+ bmppaintcsr(pos, char_white);
+ kd_curpos = pos;
+}
+
+/*
+ * bmppaintcsr: paint cursor bits.
+ */
+void
+bmppaintcsr(
+ csrpos_t pos,
+ u_char val)
+{
+ short xbit, ybit;
+ u_char *cp;
+ short line, byte;
+
+ bmpch2bit(pos, &xbit, &ybit);
+ ybit += char_height; /* position at bottom of line */
+ cp = bit2fbptr(xbit, ybit);
+ for (line = 0; line < cursor_height; ++line) {
+ for (byte = 0; byte < char_byte_width; ++byte)
+ *(cp+byte) = val;
+ cp += fb_byte_width;
+ }
+}
+
+/*
+ * bmpch2bit: convert character position to x and y bit addresses.
+ * (0, 0) is the upper left corner.
+ */
+void
+bmpch2bit(
+ csrpos_t pos,
+ short *xb,
+ short *yb) /* x, y bit positions, u/l corner */
+{
+ short xch, ych;
+
+ xch = (pos / ONE_SPACE) % kd_cols;
+ ych = pos / (ONE_SPACE * kd_cols);
+ *xb = xstart + xch * char_width;
+ *yb = ystart + ych * (char_height + cursor_height);
+}
+
+/*
+ * bit2fbptr: return a pointer into the frame buffer corresponding to
+ * the bit address (x, y).
+ * Assumes that xb and yb don't point to the middle of a
+ * byte.
+ */
+u_char *
+bit2fbptr(
+ short xb,
+ short yb)
+{
+ return(vid_start + yb * fb_byte_width + xb/8);
+}
+
+
+/*
+ * console stuff
+ */
+
+/*
+ * XXX we assume that pcs *always* have a console
+ */
+int
+kdcnprobe(struct consdev *cp)
+{
+ int maj, unit, pri;
+
+ maj = 0;
+ unit = 0;
+ pri = CN_INTERNAL;
+
+ cp->cn_dev = makedev(maj, unit);
+ cp->cn_pri = pri;
+ return 0;
+}
+
+int
+kdcninit(struct consdev *cp)
+{
+ kdinit();
+ return 0;
+}
+
+int
+kdcngetc(dev_t dev, int wait)
+{
+ if (wait) {
+ int c;
+ while ((c = kdcnmaygetc()) < 0)
+ continue;
+ return c;
+ }
+ else
+ return kdcnmaygetc();
+}
+
+int
+kdcnputc(dev_t dev, int c)
+{
+ if (!kd_initialized)
+ return -1;
+
+ /* Note that tab is handled in kd_putc */
+ if (c == '\n')
+ kd_putc('\r');
+ kd_putc_esc(c);
+
+ return 0;
+}
+
+/*
+ * kdcnmaygetc:
+ *
+ * Get one character using polling, rather than interrupts. Used
+ * by the kernel debugger. Note that Caps Lock is ignored.
+ * Normally this routine is called with interrupts already
+ * disabled, but there is code in place so that it will be more
+ * likely to work even if interrupts are turned on.
+ */
+int
+kdcnmaygetc(void)
+{
+ unsigned char c;
+ unsigned char scancode;
+ unsigned int char_idx;
+#ifdef notdef
+ spl_t o_pri;
+#endif
+ boolean_t up;
+
+ if (! kd_initialized)
+ return -1;
+
+ kd_extended = FALSE;
+#ifdef notdef
+ o_pri = splhi();
+#endif
+ for ( ; ; ) {
+ if (!(inb(K_STATUS) & K_OBUF_FUL))
+ return -1;
+
+ up = FALSE;
+ /*
+ * We'd come here for mouse events in debugger, if
+ * the mouse were on.
+ */
+ if ((inb(K_STATUS) & 0x20) == 0x20) {
+ printf("M%xP", inb(K_RDWR));
+ continue;
+ }
+ scancode = inb(K_RDWR);
+ /*
+ * Handle extend modifier and
+ * ack/resend, otherwise we may never receive
+ * a key.
+ */
+ if (scancode == K_EXTEND) {
+ kd_extended = TRUE;
+ continue;
+ } else if (scancode == K_RESEND) {
+ printf("cngetc: resend");
+ kd_resend();
+ continue;
+ } else if (scancode == K_ACKSC) {
+ printf("cngetc: handle_ack");
+ kd_handle_ack();
+ continue;
+ }
+ if (scancode & K_UP) {
+ up = TRUE;
+ scancode &= ~K_UP;
+ }
+ if (kd_kbd_mouse)
+ kd_kbd_magic(scancode);
+ if (scancode < NUMKEYS) {
+ /* Lookup in map, then process. */
+ char_idx = kdstate2idx(kd_state, kd_extended);
+ c = key_map[scancode][char_idx];
+ if (c == K_SCAN) {
+ c = key_map[scancode][++char_idx];
+ kd_state = do_modifier(kd_state, c, up);
+#ifdef notdef
+ cnsetleds(state2leds(kd_state));
+#endif
+ } else if (! up
+ && c == K_ESC
+ && key_map[scancode][char_idx+1] == 0x5b) {
+ /* As a convenience for the nice
+ people using our debugger, remap
+ some keys to the readline-like
+ shortcuts supported by dde.
+
+ XXX This is a workaround for the
+ limited kernel getchar interface.
+ It is only used by the debugger. */
+ c = key_map[scancode][char_idx+2];
+ switch (c) {
+#define _MAP(A,B,C) (C)
+#define MAP(T) _MAP(T)
+#define CTRL(c) ((c) & 0x1f)
+ case MAP(K_HOME): c = CTRL('a'); break;
+ case MAP(K_UA): c = CTRL('p'); break;
+ case MAP(K_LA): c = CTRL('b'); break;
+ case MAP(K_RA): c = CTRL('f'); break;
+ case MAP(K_DA): c = CTRL('n'); break;
+ case MAP(K_END): c = CTRL('e'); break;
+ /* delete */
+ case 0x39: c = CTRL('d'); break;
+#undef CTRL
+#undef MAP
+#undef _MAP
+ default:
+ /* Retain the old behavior. */
+ c = K_ESC;
+ }
+
+ return(c);
+ } else if (!up) {
+ /* regular key-down */
+ if (c == K_CR)
+ c = K_LF;
+#ifdef notdef
+ splx(o_pri);
+#endif
+ return(c & 0177);
+ }
+ }
+ }
+}
diff --git a/i386/i386at/kd.h b/i386/i386at/kd.h
new file mode 100644
index 0000000..5bfabce
--- /dev/null
+++ b/i386/i386at/kd.h
@@ -0,0 +1,744 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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: kd.h
+ Description: definitions for AT keyboard/display driver
+ Authors: Eugene Kuerner, Adrienne Jardetzky, Mike Kupfer
+
+ $ Header: $
+
+ Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989.
+ All rights reserved.
+********************************************************************** */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * This file contains defines and structures that implement hardware
+ * keyboard mapping into ansi defined output codes. Note that this
+ * is structured so that "re-mapping" of actual keys is allowed at
+ * anytime during execution of the console driver. And each scan code
+ * is potentially expanded into NUMKEYS characters. Which is programmable
+ * at runtime or whenever.
+ *
+ * 02 Nov 1988 orc!eugene
+ *
+ */
+
+#ifndef _KD_H_
+#define _KD_H_
+
+#include <device/input.h>
+#include <mach/boolean.h>
+#include <sys/types.h>
+#include <device/cons.h>
+#include <device/io_req.h>
+#include <device/buf.h>
+#include <device/input.h>
+#include <device/tty.h>
+#include <i386at/kdsoft.h>
+
+/*
+ * Where memory for various graphics adapters starts.
+ */
+#define EGA_START 0x0b8000
+#define CGA_START 0x0b8000
+#define MONO_START 0x0b0000
+
+/*
+ * Common I/O ports.
+ */
+#define K_TMR0 0x40 /* timer 0, 1, or 2 value (r/w) */
+#define K_TMR1 0x41
+#define K_TMR2 0x42
+#define K_TMRCTL 0x43 /* timer control (write-only) */
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_PORTB 0x61 /* r/w. speaker & status lines */
+#define K_STATUS 0x64 /* keybd status (read-only) */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+/*
+ * I/O ports for various graphics adapters.
+ */
+#define EGA_IDX_REG 0x3d4
+#define EGA_IO_REG 0x3d5
+#define CGA_IDX_REG 0x3d4
+#define CGA_IO_REG 0x3d5
+#define MONO_IDX_REG 0x3b4
+#define MONO_IO_REG 0x3b5
+
+/*
+ * Commands sent to graphics adapter.
+ */
+#define C_START 0x0a /* return cursor line start */
+#define C_STOP 0x0b /* return cursor line stop */
+#define C_LOW 0x0f /* return low byte of cursor addr */
+#define C_HIGH 0x0e /* high byte */
+
+/*
+ * Bit definitions for K_STATUS port.
+ */
+#define K_OBUF_FUL 0x01 /* output (from keybd) buffer full */
+#define K_IBUF_FUL 0x02 /* input (to keybd) buffer full */
+#define K_SYSFLAG 0x04 /* "System Flag" */
+#define K_CMD_DATA 0x08 /* 1 = input buf has cmd, 0 = data */
+#define K_KBD_INHBT 0x10 /* 0 if keyboard inhibited */
+
+/*
+ * Keyboard controller commands (sent to K_CMD port).
+ */
+#define KC_CMD_READ 0x20 /* read controller command byte */
+#define KC_CMD_WRITE 0x60 /* write controller command byte */
+#define KC_CMD_TEST 0xab /* test interface */
+#define KC_CMD_DUMP 0xac /* diagnostic dump */
+#define KC_CMD_DISBLE 0xad /* disable keyboard */
+#define KC_CMD_ENBLE 0xae /* enable keyboard */
+#define KC_CMD_RDKBD 0xc4 /* read keyboard ID */
+#define KC_CMD_ECHO 0xee /* used for diagnostic testing */
+
+/*
+ * Keyboard commands (send to K_RDWR).
+ */
+#define K_CMD_LEDS 0xed /* set status LEDs (caps lock, etc.) */
+
+/*
+ * Bit definitions for controller command byte (sent following
+ * K_CMD_WRITE command).
+ */
+#define K_CB_ENBLIRQ 0x01 /* enable data-ready intrpt */
+#define K_CB_SETSYSF 0x04 /* Set System Flag */
+#define K_CB_INHBOVR 0x08 /* Inhibit Override */
+#define K_CB_DISBLE 0x10 /* disable keyboard */
+
+/*
+ * Bit definitions for "Indicator Status Byte" (sent after a
+ * K_CMD_LEDS command). If the bit is on, the LED is on. Undefined
+ * bit positions must be 0.
+ */
+#define K_LED_SCRLLK 0x1 /* scroll lock */
+#define K_LED_NUMLK 0x2 /* num lock */
+#define K_LED_CAPSLK 0x4 /* caps lock */
+
+/*
+ * Bit definitions for "Miscellaneous port B" (K_PORTB).
+ */
+/* read/write */
+#define K_ENABLETMR2 0x01 /* enable output from timer 2 */
+#define K_SPKRDATA 0x02 /* direct input to speaker */
+#define K_ENABLEPRTB 0x04 /* "enable" port B */
+#define K_EIOPRTB 0x08 /* enable NMI on parity error */
+/* read-only */
+#define K_REFRESHB 0x10 /* refresh flag from INLTCONT PAL */
+#define K_OUT2B 0x20 /* timer 2 output */
+#define K_ICKB 0x40 /* I/O channel check (parity error) */
+
+/*
+ * Bit definitions for timer control port (K_TMRCTL).
+ */
+/* select timer 0, 1, or 2. Don't mess with 0 or 1. */
+#define K_SELTMRMASK 0xc0
+#define K_SELTMR0 0x00
+#define K_SELTMR1 0x40
+#define K_SELTMR2 0x80
+
+/* read/load control */
+#define K_RDLDTMRMASK 0x30
+#define K_HOLDTMR 0x00 /* freeze timer until read */
+#define K_RDLDTLSB 0x10 /* read/load LSB */
+#define K_RDLDTMSB 0x20 /* read/load MSB */
+#define K_RDLDTWORD 0x30 /* read/load LSB then MSB */
+
+/* mode control */
+#define K_TMDCTLMASK 0x0e
+#define K_TCOUNTINTR 0x00 /* "Term Count Intr" */
+#define K_TONESHOT 0x02 /* "Progr One-Shot" */
+#define K_TRATEGEN 0x04 /* "Rate Gen (/n)" */
+#define K_TSQRWAVE 0x06 /* "Sqr Wave Gen" */
+#define K_TSOFTSTRB 0x08 /* "Softw Trig Strob" */
+#define K_THARDSTRB 0x0a /* "Hardw Trig Strob" */
+
+/* count mode */
+#define K_TCNTMDMASK 0x01
+#define K_TBINARY 0x00 /* 16-bit binary counter */
+#define K_TBCD 0x01 /* 4-decade BCD counter */
+
+
+
+/*
+ * Fun definitions for displayed characters and characters read from
+ * the keyboard.
+ */
+
+/*
+ * Attributes for character sent to display.
+ */
+#define KA_NORMAL 0x07
+#define KA_REVERSE 0x70
+
+#define KAX_REVERSE 0x01
+#define KAX_UNDERLINE 0x02
+#define KAX_BLINK 0x04
+#define KAX_BOLD 0x08
+#define KAX_DIM 0x10
+#define KAX_INVISIBLE 0x20
+
+#define KAX_COL_UNDERLINE 0x0f /* bright white */
+#define KAX_COL_DIM 0x08 /* gray */
+
+/*
+ * For an EGA-like display, each character takes two bytes, one for the
+ * actual character, followed by one for its attributes.
+ * Be very careful if you change ONE_SPACE, as these constants are also used
+ * to define the device-independent display implemented by kd.c.
+ * (See kdsoft.h for more details on the device-independent display.)
+ */
+#define ONE_SPACE 2 /* bytes in 1 char, EGA-like display */
+#define BOTTOM_LINE 3840 /* 1st byte in last line of display */
+#define ONE_PAGE 4000 /* number of bytes in page */
+#define ONE_LINE 160 /* number of bytes in line */
+
+#define BEG_OF_LINE(pos) ((pos) - (pos)%ONE_LINE)
+#define CURRENT_COLUMN(pos) (((pos) % ONE_LINE) / ONE_SPACE)
+
+#define NUMKEYS 89
+#define NUMSTATES 5 /* NORM_STATE, ... */
+#define NUMOUTPUT 3 /* max size of byte seq from key */
+#define WIDTH_KMAP (NUMSTATES * NUMOUTPUT)
+
+/*
+ * Keyboard states. Used for KDGKBENT, KDSKBENT ioctl's. If you
+ * change these values, you should also rearrange the entries in
+ * key_map.
+ */
+/* "state indices" (for computing key_map index) */
+#define NORM_STATE 0
+#define SHIFT_STATE 1
+#define CTRL_STATE 2
+#define ALT_STATE 3
+#define SHIFT_ALT 4
+/* macro to convert from state index to actual key_map index */
+#define CHARIDX(sidx) ((sidx) * NUMOUTPUT)
+ /* where sidx is in [NORM_STATE ... SHIFT_ALT] */
+
+/* "state bits" for kd_state vector */
+#define KS_NORMAL 0x00
+#define KS_SLKED 0x01
+#define KS_NLKED 0x02
+#define KS_CLKED 0x04
+#define KS_ALTED 0x08
+#define KS_SHIFTED 0x10
+#define KS_CTLED 0x20
+
+
+/* special codes */
+#define K_UP 0x80 /* OR'd in if key below is released */
+#define K_EXTEND 0xe0 /* marker for "extended" sequence */
+#define K_ACKSC 0xfa /* ack for keyboard command */
+#define K_RESEND 0xfe /* request to resend keybd cmd */
+
+/* modifier keys */
+#define K_CTLSC 0x1d /* control down */
+#define K_LSHSC 0x2a /* left shift down */
+#define K_RSHSC 0x36 /* right shift down */
+#define K_ALTSC 0x38 /* alt key down */
+#define K_CLCKSC 0x3a /* caps lock */
+#define K_NLCKSC 0x45 /* num lock down */
+
+/* "special keys" */
+#define K_BSSC 0x0e /* backspace */
+#define K_TABSC 0x0f /* tab */
+#define K_RETSC 0x1c /* return */
+#define K_SPSC 0x39 /* space */
+#define K_ESCSC 0x01 /* ESC */
+
+/* alphabetic keys */
+#define K_qSC 0x10
+#define K_wSC 0x11
+#define K_eSC 0x12
+#define K_rSC 0x13
+#define K_tSC 0x14
+#define K_ySC 0x15
+#define K_uSC 0x16
+#define K_iSC 0x17
+#define K_oSC 0x18
+#define K_pSC 0x19
+
+#define K_aSC 0x1e
+#define K_sSC 0x1f
+#define K_dSC 0x20
+#define K_fSC 0x21
+#define K_gSC 0x22
+#define K_hSC 0x23
+#define K_jSC 0x24
+#define K_kSC 0x25
+#define K_lSC 0x26
+
+#define K_zSC 0x2c
+#define K_xSC 0x2d
+#define K_cSC 0x2e
+#define K_vSC 0x2f
+#define K_bSC 0x30
+#define K_nSC 0x31
+#define K_mSC 0x32
+
+/* numbers and punctuation */
+#define K_ONESC 0x02 /* 1 */
+#define K_TWOSC 0x03 /* 2 */
+#define K_THREESC 0x04 /* 3 */
+#define K_FOURSC 0x05 /* 4 */
+#define K_FIVESC 0x06 /* 5 */
+#define K_SIXSC 0x07 /* 6 */
+#define K_SEVENSC 0x08 /* 7 */
+#define K_EIGHTSC 0x09 /* 8 */
+#define K_NINESC 0x0a /* 9 */
+#define K_ZEROSC 0x0b /* 0 */
+
+#define K_MINUSSC 0x0c /* - */
+#define K_EQLSC 0x0d /* = */
+#define K_LBRKTSC 0x1a /* [ */
+#define K_RBRKTSC 0x1b /* ] */
+#define K_SEMISC 0x27 /* ; */
+#define K_SQUOTESC 0x28 /* ' */
+#define K_GRAVSC 0x29 /* ` */
+#define K_BSLSHSC 0x2b /* \ */
+#define K_COMMASC 0x33 /* , */
+#define K_PERIODSC 0x34 /* . */
+#define K_SLASHSC 0x35 /* / */
+
+/* keypad keys */
+#define K_HOMESC 0x47 /* scancode for home */
+#define K_DELSC 0x53 /* scancode for del */
+
+/*
+ * Ascii values and flag characters for key map.
+ * A function key is represented by the 3-byte char sequence that it
+ * corresponds to.
+ * Other mappable non-Ascii keys (e.g., "ctrl") are represented by a
+ * two-byte sequence: K_SCAN, followed by the key's scan code.
+ */
+#define K_DONE 0xffu /* must be same as NC */
+#define NC 0xffu /* No character defined */
+
+#define K_SCAN 0xfeu /* followed by scan code */
+
+/* ascii char set */
+#define K_NUL 0x00 /* Null character */
+#define K_SOH 0x01
+#define K_STX 0x02
+#define K_ETX 0x03
+#define K_EOT 0x04
+#define K_ENQ 0x05
+#define K_ACK 0x06
+#define K_BEL 0x07 /* bell character */
+#define K_BS 0x08 /* back space */
+#define K_HT 0x09
+#define K_LF 0x0a /* line feed */
+#define K_VT 0x0b
+#define K_FF 0x0c
+#define K_CR 0x0d /* carriage return */
+#define K_SO 0x0e
+#define K_SI 0x0f
+#define K_DLE 0x10
+#define K_DC1 0x11
+#define K_DC2 0x12
+#define K_DC3 0x13
+#define K_DC4 0x14
+#define K_NAK 0x15
+#define K_SYN 0x16
+#define K_ETB 0x17
+#define K_CAN 0x18
+#define K_EM 0x19
+#define K_SUB 0x1a
+#define K_ESC 0x1b /* escape character */
+#define K_FS 0x1c
+#define K_GS 0x1d
+#define K_RS 0x1e
+#define K_US 0x1f
+#define K_SPACE 0x20 /* space character */
+#define K_BANG 0x21 /* ! */
+#define K_DQUOTE 0x22 /* " */
+#define K_POUND 0x23 /* # */
+#define K_DOLLAR 0x24 /* $ */
+#define K_PERC 0x25 /* % */
+#define K_AMPER 0x26 /* & */
+#define K_SQUOTE 0x27 /* ' */
+#define K_LPAREN 0x28 /* ( */
+#define K_RPAREN 0x29 /* ) */
+#define K_ASTER 0x2a /* * */
+#define K_PLUS 0x2b /* + */
+#define K_COMMA 0x2c /* , */
+#define K_MINUS 0x2d /* - */
+#define K_PERIOD 0x2e /* . */
+#define K_SLASH 0x2f /* / */
+#define K_ZERO 0x30 /* 0 */
+#define K_ONE 0x31 /* 1 */
+#define K_TWO 0x32 /* 2 */
+#define K_THREE 0x33 /* 3 */
+#define K_FOUR 0x34 /* 4 */
+#define K_FIVE 0x35 /* 5 */
+#define K_SIX 0x36 /* 6 */
+#define K_SEVEN 0x37 /* 7 */
+#define K_EIGHT 0x38 /* 8 */
+#define K_NINE 0x39 /* 9 */
+#define K_COLON 0x3a /* : */
+#define K_SEMI 0x3b /* ; */
+#define K_LTHN 0x3c /* < */
+#define K_EQL 0x3d /* = */
+#define K_GTHN 0x3e /* > */
+#define K_QUES 0x3f /* ? */
+#define K_ATSN 0x40 /* @ */
+#define K_A 0x41 /* A */
+#define K_B 0x42 /* B */
+#define K_C 0x43 /* C */
+#define K_D 0x44 /* D */
+#define K_E 0x45 /* E */
+#define K_F 0x46 /* F */
+#define K_G 0x47 /* G */
+#define K_H 0x48 /* H */
+#define K_I 0x49 /* I */
+#define K_J 0x4a /* J */
+#define K_K 0x4b /* K */
+#define K_L 0x4c /* L */
+#define K_M 0x4d /* M */
+#define K_N 0x4e /* N */
+#define K_O 0x4f /* O */
+#define K_P 0x50 /* P */
+#define K_Q 0x51 /* Q */
+#define K_R 0x52 /* R */
+#define K_S 0x53 /* S */
+#define K_T 0x54 /* T */
+#define K_U 0x55 /* U */
+#define K_V 0x56 /* V */
+#define K_W 0x57 /* W */
+#define K_X 0x58 /* X */
+#define K_Y 0x59 /* Y */
+#define K_Z 0x5a /* Z */
+#define K_LBRKT 0x5b /* [ */
+#define K_BSLSH 0x5c /* \ */
+#define K_RBRKT 0x5d /* ] */
+#define K_CARET 0x5e /* ^ */
+#define K_UNDSC 0x5f /* _ */
+#define K_GRAV 0x60 /* ` */
+#define K_a 0x61 /* a */
+#define K_b 0x62 /* b */
+#define K_c 0x63 /* c */
+#define K_d 0x64 /* d */
+#define K_e 0x65 /* e */
+#define K_f 0x66 /* f */
+#define K_g 0x67 /* g */
+#define K_h 0x68 /* h */
+#define K_i 0x69 /* i */
+#define K_j 0x6a /* j */
+#define K_k 0x6b /* k */
+#define K_l 0x6c /* l */
+#define K_m 0x6d /* m */
+#define K_n 0x6e /* n */
+#define K_o 0x6f /* o */
+#define K_p 0x70 /* p */
+#define K_q 0x71 /* q */
+#define K_r 0x72 /* r */
+#define K_s 0x73 /* s */
+#define K_t 0x74 /* t */
+#define K_u 0x75 /* u */
+#define K_v 0x76 /* v */
+#define K_w 0x77 /* w */
+#define K_x 0x78 /* x */
+#define K_y 0x79 /* y */
+#define K_z 0x7a /* z */
+#define K_LBRACE 0x7b /* { */
+#define K_PIPE 0x7c /* | */
+#define K_RBRACE 0x7d /* } */
+#define K_TILDE 0x7e /* ~ */
+#define K_DEL 0x7f /* delete */
+
+/* Ascii sequences to be generated by the named key */
+#define K_F1 0x1b,0x4f,0x50
+#define K_F1S 0x1b,0x4f,0x70
+#define K_F2 0x1b,0x4f,0x51
+#define K_F2S 0x1b,0x4f,0x71
+#define K_F3 0x1b,0x4f,0x52
+#define K_F3S 0x1b,0x4f,0x72
+#define K_F4 0x1b,0x4f,0x53
+#define K_F4S 0x1b,0x4f,0x73
+#define K_F5 0x1b,0x4f,0x54
+#define K_F5S 0x1b,0x4f,0x74
+#define K_F6 0x1b,0x4f,0x55
+#define K_F6S 0x1b,0x4f,0x75
+#define K_F7 0x1b,0x4f,0x56
+#define K_F7S 0x1b,0x4f,0x76
+#define K_F8 0x1b,0x4f,0x57
+#define K_F8S 0x1b,0x4f,0x77
+#define K_F9 0x1b,0x4f,0x58
+#define K_F9S 0x1b,0x4f,0x78
+#define K_F10 0x1b,0x4f,0x59
+#define K_F10S 0x1b,0x4f,0x79
+#define K_F11 0x1b,0x4f,0x5a
+#define K_F11S 0x1b,0x4f,0x7a
+#define K_F12 0x1b,0x4f,0x41
+#define K_F12S 0x1b,0x4f,0x61
+
+/* These are the Alt-FxxA #defines. They work with the new keymap
+ -- Derek Upham 1997/06/25 */
+#define K_F1A 0x1b,0x4f,0x30
+#define K_F2A 0x1b,0x4f,0x31
+#define K_F3A 0x1b,0x4f,0x32
+#define K_F4A 0x1b,0x4f,0x33
+#define K_F5A 0x1b,0x4f,0x34
+#define K_F6A 0x1b,0x4f,0x35
+#define K_F7A 0x1b,0x4f,0x36
+#define K_F8A 0x1b,0x4f,0x37
+#define K_F9A 0x1b,0x4f,0x38
+#define K_F10A 0x1b,0x4f,0x39
+#define K_F11A 0x1b,0x4f,0x3a
+#define K_F12A 0x1b,0x4f,0x3b
+
+#define K_SCRL 0x1b,0x5b,0x4d
+#define K_HOME 0x1b,0x5b,0x48
+#define K_UA 0x1b,0x5b,0x41
+#define K_PUP 0x1b,0x5b,0x56
+#define K_LA 0x1b,0x5b,0x44
+#define K_RA 0x1b,0x5b,0x43
+#define K_END 0x1b,0x5b,0x59
+#define K_DA 0x1b,0x5b,0x42
+#define K_PDN 0x1b,0x5b,0x55
+#define K_INS 0x1b,0x5b,0x40
+
+#define KBD_IRQ 1
+
+/*
+ * This array maps scancodes to Ascii characters (or character
+ * sequences).
+ * The first index is the scancode. The first NUMOUTPUT characters
+ * (accessed using the second index) correspond to the key's char
+ * sequence for the Normal state. The next NUMOUTPUT characters
+ * are for the Shift state, then Ctrl, then Alt, then Shift/Alt.
+ */
+#ifdef KERNEL
+extern u_char key_map[NUMKEYS][WIDTH_KMAP];
+#endif /* KERNEL */
+
+
+
+/*
+ * These routines are declared here so that all the modules making
+ * up the kd driver agree on how to do locking.
+ */
+
+#ifdef KERNEL
+#include <i386/machspl.h>
+#define SPLKD spltty
+#endif /* KERNEL */
+
+
+/*
+ * Ioctl's on /dev/console.
+ */
+
+/*
+ * KDGKBENT, KDSKBENT - Get and set keyboard table entry. Useful for
+ * remapping keys.
+ *
+ * KDGSTATE - Get the keyboard state variable, which flags the
+ * modifier keys (shift, ctrl, etc.) that are down. See
+ * KS_NORMAL et al above. Used for debugging.
+ *
+ * KDSETBELL - Turns the bell on or off.
+ */
+
+#define KDGKBENT _IOWR('k', 1, struct kbentry) /* get keybd entry */
+
+#define KDSKBENT _IOW('k', 2, struct kbentry) /* set keybd entry */
+
+#define KDGSTATE _IOR('k', 3, int) /* get keybd state */
+
+#define KDSETBELL _IOW('k', 4, int) /* turn bell on or off */
+# define KD_BELLON 1
+# define KD_BELLOFF 0
+
+/*
+ * This struct is used for getting and setting key definitions. The
+ * values for kb_index are obtainable from the man page for
+ * keyboard(7) (though they should really be defined here!).
+ */
+struct kbentry {
+ u_char kb_state; /* which state to use */
+ u_char kb_index; /* which keycode */
+ u_char kb_value[NUMOUTPUT]; /* value to get/set */
+};
+
+
+/*
+ * Ioctl's on /dev/kbd.
+ */
+
+#ifdef KERNEL
+extern int kb_mode;
+#endif
+
+struct X_kdb {
+ u_int *ptr;
+ u_int size;
+};
+
+#define K_X_KDB_ENTER _IOW('K', 16, struct X_kdb)
+#define K_X_KDB_EXIT _IOW('K', 17, struct X_kdb)
+
+#define K_X_IN 0x01000000
+#define K_X_OUT 0x02000000
+#define K_X_BYTE 0x00010000
+#define K_X_WORD 0x00020000
+#define K_X_LONG 0x00040000
+#define K_X_TYPE 0x03070000
+#define K_X_PORT 0x0000ffff
+
+extern boolean_t kd_isupper (u_char);
+extern boolean_t kd_islower (u_char);
+extern void kd_senddata (unsigned char);
+extern void kd_sendcmd (unsigned char);
+extern void kd_cmdreg_write (int);
+extern void kd_mouse_drain (void);
+extern void set_kd_state (int);
+extern void kd_setleds1 (u_char);
+extern void kd_setleds2 (void);
+extern void cnsetleds (u_char);
+extern void kdreboot (void);
+extern void kd_putc_esc (u_char);
+extern void kd_putc (u_char);
+extern void kd_parseesc (void);
+extern void kd_down (void);
+extern void kd_up (void);
+extern void kd_cr (void);
+extern void kd_tab (void);
+extern void kd_left (void);
+extern void kd_right (void);
+extern void kd_scrollup (void);
+extern void kd_scrolldn (void);
+extern void kd_cls (void);
+extern void kd_home (void);
+extern void kd_insch (int number);
+extern void kd_cltobcur (void);
+extern void kd_cltopcur (void);
+extern void kd_cltoecur (void);
+extern void kd_clfrbcur (void);
+extern void kd_eraseln (void);
+extern void kd_insln (int);
+extern void kd_delln (int);
+extern void kd_delch (int);
+extern void kd_erase (int);
+extern void kd_bellon (void);
+extern void kd_belloff (void *param);
+extern void kdinit (void);
+extern int kdsetkbent (struct kbentry *, int);
+extern int kdgetkbent (struct kbentry *);
+extern int kdsetbell (int, int);
+extern void kd_resend (void);
+extern void kd_handle_ack (void);
+extern int kd_kbd_magic (int);
+extern unsigned int kdstate2idx (unsigned int, boolean_t);
+extern void kd_parserest (u_char *);
+extern int kdcnprobe(struct consdev *cp);
+extern int kdcninit(struct consdev *cp);
+extern int kdcngetc(dev_t dev, int wait);
+extern int kdcnmaygetc (void);
+extern int kdcnputc(dev_t dev, int c);
+extern void kd_setpos(csrpos_t newpos);
+
+extern void kd_slmwd (void *start, int count, int value);
+extern void kd_slmscu (void *from, void *to, int count);
+extern void kd_slmscd (void *from, void *to, int count);
+
+extern void kdintr(int vec);
+
+#if MACH_KDB
+#include <ddb/db_input.h>
+#endif /* MACH_KDB */
+
+extern int kdopen(dev_t dev, int flag, io_req_t ior);
+extern void kdclose(dev_t dev, int flag);
+extern int kdread(dev_t dev, io_req_t uio);
+extern int kdwrite(dev_t dev, io_req_t uio);
+
+extern io_return_t kdgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t *count);
+
+extern io_return_t kdsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count);
+
+extern int kdportdeath(dev_t dev, mach_port_t port);
+extern vm_offset_t kdmmap(dev_t dev, vm_offset_t off, vm_prot_t prot);
+
+boolean_t kdcheckmagic(Scancode scancode);
+
+int do_modifier(int state, Scancode c, boolean_t up);
+
+/*
+ * Generic routines for bitmap devices (i.e., assume no hardware
+ * assist). Assumes a simple byte ordering (i.e., a byte at a lower
+ * address is to the left of the byte at the next higher address).
+ * For the 82786, this works anyway if the characters are 2 bytes
+ * wide. (more bubble gum and paper clips.)
+ *
+ * See the comments above (in i386at/kd.c) about SLAMBPW.
+ */
+void bmpch2bit(csrpos_t pos, short *xb, short *yb);
+void bmppaintcsr(csrpos_t pos, u_char val);
+u_char *bit2fbptr(short xb, short yb);
+
+unsigned char kd_getdata(void);
+unsigned char state2leds(int state);
+
+void kdstart(struct tty *tp);
+void kdstop(struct tty *tp, int flags);
+
+void kd_xga_init(void);
+
+#endif /* _KD_H_ */
diff --git a/i386/i386at/kd_event.c b/i386/i386at/kd_event.c
new file mode 100644
index 0000000..247d95b
--- /dev/null
+++ b/i386/i386at/kd_event.c
@@ -0,0 +1,392 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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: kd_event.c
+ Description: Driver for event interface to keyboard.
+
+ $ Header: $
+
+ Copyright Ing. C. Olivetti & C. S.p.A. 1989. All rights reserved.
+********************************************************************** */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <mach/boolean.h>
+#include <sys/types.h>
+#include <kern/printf.h>
+#include <string.h>
+
+#include <device/ds_routines.h>
+#include <device/device_types.h>
+#include <device/io_req.h>
+#include <i386/machspl.h>
+#include <i386/pio.h>
+#include <i386at/kd.h>
+#include <i386at/kd_queue.h>
+#ifdef APIC
+# include <i386/apic.h>
+#else
+# include <i386/pic.h>
+#endif
+
+#include "kd_event.h"
+
+/*
+ * Code for /dev/kbd. The interrupt processing is done in kd.c,
+ * which calls into this module to enqueue scancode events when
+ * the keyboard is in Event mode.
+ */
+
+/*
+ * Note: These globals are protected by raising the interrupt level
+ * via SPLKD.
+ */
+
+kd_event_queue kbd_queue; /* queue of keyboard events */
+queue_head_t kbd_read_queue = { &kbd_read_queue, &kbd_read_queue };
+
+static boolean_t initialized = FALSE;
+
+
+/*
+ * kbdinit - set up event queue.
+ */
+
+static void
+kbdinit(void)
+{
+ spl_t s = SPLKD();
+
+ if (!initialized) {
+ kdq_reset(&kbd_queue);
+ initialized = TRUE;
+ }
+ splx(s);
+}
+
+
+/*
+ * kbdopen - Verify that open is read-only and remember process
+ * group leader.
+ */
+
+/*ARGSUSED*/
+int
+kbdopen(dev_t dev, int flags, io_req_t ior)
+{
+ spl_t o_pri = spltty();
+ kdinit();
+ splx(o_pri);
+ kbdinit();
+
+ return(0);
+}
+
+
+/*
+ * kbdclose - Make sure that the kd driver is in Ascii mode and
+ * reset various flags.
+ */
+
+/*ARGSUSED*/
+void
+kbdclose(
+ dev_t dev,
+ int flags)
+{
+ spl_t s = SPLKD();
+
+ kb_mode = KB_ASCII;
+ kdq_reset(&kbd_queue);
+ splx(s);
+}
+
+
+io_return_t kbdgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data, /* pointer to OUT array */
+ mach_msg_type_number_t *count) /* OUT */
+{
+ switch (flavor) {
+ case KDGKBDTYPE:
+ *data = KB_VANILLAKB;
+ *count = 1;
+ break;
+ case DEV_GET_SIZE:
+ data[DEV_GET_SIZE_DEVICE_SIZE] = 0;
+ data[DEV_GET_SIZE_RECORD_SIZE] = sizeof(kd_event);
+ *count = DEV_GET_SIZE_COUNT;
+ break;
+ default:
+ return (D_INVALID_OPERATION);
+ }
+ return (D_SUCCESS);
+}
+
+io_return_t kbdsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count)
+{
+ switch (flavor) {
+ case KDSKBDMODE:
+ kb_mode = *data;
+ /* XXX - what to do about unread events? */
+ /* XXX - should check that 'data' contains an OK valud */
+ break;
+ case KDSETLEDS:
+ if (count != 1)
+ return (D_INVALID_OPERATION);
+ kd_setleds1 (*data);
+ break;
+ case K_X_KDB_ENTER:
+ return X_kdb_enter_init((unsigned int *)data, count);
+ case K_X_KDB_EXIT:
+ return X_kdb_exit_init((unsigned int *)data, count);
+ default:
+ return (D_INVALID_OPERATION);
+ }
+ return (D_SUCCESS);
+}
+
+
+
+/*
+ * kbdread - dequeue and return any queued events.
+ */
+int
+kbdread(
+ dev_t dev,
+ io_req_t ior)
+{
+ int err, count;
+ spl_t s;
+
+ /* Check if IO_COUNT is a multiple of the record size. */
+ if (ior->io_count % sizeof(kd_event) != 0)
+ return D_INVALID_SIZE;
+
+ err = device_read_alloc(ior, (vm_size_t)ior->io_count);
+ if (err != KERN_SUCCESS)
+ return (err);
+
+ s = SPLKD();
+ if (kdq_empty(&kbd_queue)) {
+ if (ior->io_mode & D_NOWAIT) {
+ splx(s);
+ return (D_WOULD_BLOCK);
+ }
+ ior->io_done = kbd_read_done;
+ enqueue_tail(&kbd_read_queue, (queue_entry_t) ior);
+ splx(s);
+ return (D_IO_QUEUED);
+ }
+ count = 0;
+ while (!kdq_empty(&kbd_queue) && count < ior->io_count) {
+ kd_event *ev;
+
+ ev = kdq_get(&kbd_queue);
+ *(kd_event *)(&ior->io_data[count]) = *ev;
+ count += sizeof(kd_event);
+ }
+ splx(s);
+ ior->io_residual = ior->io_count - count;
+ return (D_SUCCESS);
+}
+
+boolean_t kbd_read_done(io_req_t ior)
+{
+ int count;
+ spl_t s;
+
+ s = SPLKD();
+ if (kdq_empty(&kbd_queue)) {
+ ior->io_done = kbd_read_done;
+ enqueue_tail(&kbd_read_queue, (queue_entry_t)ior);
+ splx(s);
+ return (FALSE);
+ }
+
+ count = 0;
+ while (!kdq_empty(&kbd_queue) && count < ior->io_count) {
+ kd_event *ev;
+
+ ev = kdq_get(&kbd_queue);
+ *(kd_event *)(&ior->io_data[count]) = *ev;
+ count += sizeof(kd_event);
+ }
+ splx(s);
+
+ ior->io_residual = ior->io_count - count;
+ ds_read_done(ior);
+
+ return (TRUE);
+}
+
+
+
+/*
+ * kd_enqsc - enqueue a scancode. Should be called at SPLKD.
+ */
+
+void
+kd_enqsc(Scancode sc)
+{
+ kd_event ev;
+
+ ev.type = KEYBD_EVENT;
+ /* Not used but we set it to avoid garbage */
+ ev.unused_time.seconds = 0;
+ ev.unused_time.microseconds = 0;
+ ev.value.sc = sc;
+ kbd_enqueue(&ev);
+}
+
+
+/*
+ * kbd_enqueue - enqueue an event and wake up selecting processes, if
+ * any. Should be called at SPLKD.
+ */
+
+void
+kbd_enqueue(kd_event *ev)
+{
+ if (kdq_full(&kbd_queue))
+ printf_once("kbd: queue full\n");
+ else
+ kdq_put(&kbd_queue, ev);
+
+ {
+ io_req_t ior;
+ while ((ior = (io_req_t)dequeue_head(&kbd_read_queue)) != 0)
+ iodone(ior);
+ }
+}
+
+u_int X_kdb_enter_str[512], X_kdb_exit_str[512];
+int X_kdb_enter_len = 0, X_kdb_exit_len = 0;
+
+static void
+kdb_in_out(const u_int *p)
+{
+ int t = p[0];
+
+ switch (t & K_X_TYPE) {
+ case K_X_IN|K_X_BYTE:
+ inb(t & K_X_PORT);
+ break;
+
+ case K_X_IN|K_X_WORD:
+ inw(t & K_X_PORT);
+ break;
+
+ case K_X_IN|K_X_LONG:
+ inl(t & K_X_PORT);
+ break;
+
+ case K_X_OUT|K_X_BYTE:
+ outb(t & K_X_PORT, p[1]);
+ break;
+
+ case K_X_OUT|K_X_WORD:
+ outw(t & K_X_PORT, p[1]);
+ break;
+
+ case K_X_OUT|K_X_LONG:
+ outl(t & K_X_PORT, p[1]);
+ break;
+ }
+}
+
+void
+X_kdb_enter(void)
+{
+ u_int *u_ip, *endp;
+
+ for (u_ip = X_kdb_enter_str, endp = &X_kdb_enter_str[X_kdb_enter_len];
+ u_ip < endp;
+ u_ip += 2)
+ kdb_in_out(u_ip);
+}
+
+void
+X_kdb_exit(void)
+{
+ u_int *u_ip, *endp;
+
+ for (u_ip = X_kdb_exit_str, endp = &X_kdb_exit_str[X_kdb_exit_len];
+ u_ip < endp;
+ u_ip += 2)
+ kdb_in_out(u_ip);
+}
+
+io_return_t
+X_kdb_enter_init(
+ u_int *data,
+ u_int count)
+{
+ if (count * sizeof X_kdb_enter_str[0] > sizeof X_kdb_enter_str)
+ return D_INVALID_OPERATION;
+
+ memcpy(X_kdb_enter_str, data, count * sizeof X_kdb_enter_str[0]);
+ X_kdb_enter_len = count;
+ return D_SUCCESS;
+}
+
+io_return_t
+X_kdb_exit_init(
+ u_int *data,
+ u_int count)
+{
+ if (count * sizeof X_kdb_exit_str[0] > sizeof X_kdb_exit_str)
+ return D_INVALID_OPERATION;
+
+ memcpy(X_kdb_exit_str, data, count * sizeof X_kdb_exit_str[0]);
+ X_kdb_exit_len = count;
+ return D_SUCCESS;
+}
diff --git a/i386/i386at/kd_event.h b/i386/i386at/kd_event.h
new file mode 100644
index 0000000..7e66f76
--- /dev/null
+++ b/i386/i386at/kd_event.h
@@ -0,0 +1,62 @@
+/*
+ * Keyboard event handlers
+ * Copyright (C) 2006 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, 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, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+/*
+ * Keyboard event handling functions.
+ *
+ */
+
+#ifndef _KD_EVENT_H_
+#define _KD_EVENT_H_
+
+#include <sys/types.h>
+#include <device/io_req.h>
+#include <i386at/kd.h>
+
+extern void X_kdb_enter (void);
+
+extern void X_kdb_exit (void);
+
+extern int kbdopen(dev_t dev, int flags, io_req_t ior);
+extern void kbdclose(dev_t dev, int flags);
+extern int kbdread(dev_t dev, io_req_t ior);
+
+extern io_return_t kbdgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t *count);
+
+extern io_return_t kbdsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count);
+
+extern void kd_enqsc(Scancode sc);
+
+void kbd_enqueue(kd_event *ev);
+
+io_return_t X_kdb_enter_init(u_int *data, u_int count);
+io_return_t X_kdb_exit_init(u_int *data, u_int count);
+
+boolean_t kbd_read_done(io_req_t ior);
+
+#endif /* _KD_EVENT_H_ */
diff --git a/i386/i386at/kd_mouse.c b/i386/i386at/kd_mouse.c
new file mode 100644
index 0000000..9bd001c
--- /dev/null
+++ b/i386/i386at/kd_mouse.c
@@ -0,0 +1,800 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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: kd_mouse.c
+ Description: mouse driver as part of keyboard/display driver
+
+ $ Header: $
+
+ Copyright Ing. C. Olivetti & C. S.p.A. 1989.
+ All rights reserved.
+********************************************************************** */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * Hacked up support for serial mouse connected to COM1, using Mouse
+ * Systems 5-byte protocol at 1200 baud. This should work for
+ * Mouse Systems, SummaMouse, and Logitek C7 mice.
+ *
+ * The interface provided by /dev/mouse is a series of events as
+ * described in i386at/kd.h.
+ */
+
+#include <mach/boolean.h>
+#include <sys/types.h>
+#include <kern/printf.h>
+#include <device/ds_routines.h>
+#include <device/device_types.h>
+#include <device/io_req.h>
+#include <device/subrs.h>
+#include <i386/ipl.h>
+#include <i386/irq.h>
+#include <i386/pio.h>
+#include <chips/busses.h>
+#include <i386at/com.h>
+#include <i386at/kd.h>
+#include <i386at/kd_queue.h>
+#include <i386at/i8250.h>
+
+#include "kd_mouse.h"
+
+static interrupt_handler_fn oldvect; /* old interrupt vector */
+static int oldunit;
+extern struct bus_device *cominfo[];
+
+kd_event_queue mouse_queue; /* queue of mouse events */
+boolean_t mouse_in_use = FALSE;
+queue_head_t mouse_read_queue = { &mouse_read_queue, &mouse_read_queue };
+
+
+/*
+ * The state of the 3 buttons is encoded in the low-order 3 bits (both
+ * here and in other variables in the driver).
+ */
+u_char lastbuttons; /* previous state of mouse buttons */
+#define MOUSE_UP 1
+#define MOUSE_DOWN 0
+#define MOUSE_ALL_UP 0x7
+
+int mouse_baud = BCNT1200;
+
+boolean_t mouse_char_cmd = FALSE; /* mouse response is to cmd */
+boolean_t mouse_char_wanted = FALSE; /* want mouse response */
+int mouse_char_index; /* mouse response */
+
+#define IBM_MOUSE_IRQ 12
+
+/*
+ * init_mouse_hw - initialize the serial port.
+ */
+static void
+init_mouse_hw(dev_t unit, int mode)
+{
+ unsigned short base_addr = cominfo[unit]->address;
+
+ outb(base_addr + RIE, 0);
+ outb(base_addr + RLC, LCDLAB);
+ outb(base_addr + RDLSB, mouse_baud & 0xff);
+ outb(base_addr + RDMSB, (mouse_baud >> 8) & 0xff);
+ outb(base_addr + RLC, mode);
+ outb(base_addr + RMC, MCDTR | MCRTS | MCOUT2);
+ outb(base_addr + RIE, IERD | IELS);
+}
+
+
+/*
+ * mouseopen - Verify that the request is read-only, initialize,
+ * and remember process group leader.
+ */
+/*
+ * Low 3 bits of minor are the com port #.
+ * The high 5 bits of minor are the mouse type
+ */
+#define MOUSE_SYSTEM_MOUSE 0
+#define MICROSOFT_MOUSE 1
+#define IBM_MOUSE 2
+#define NO_MOUSE 3
+#define LOGITECH_TRACKMAN 4
+#define MICROSOFT_MOUSE7 5
+static int mouse_type;
+static int mousebufsize;
+static int mousebufindex = 0;
+int track_man[10];
+
+/*ARGSUSED*/
+int
+mouseopen(dev_t dev, int flags, io_req_t ior)
+{
+ if (mouse_in_use)
+ return (D_ALREADY_OPEN);
+ mouse_in_use = TRUE; /* locking? */
+ kdq_reset(&mouse_queue);
+ lastbuttons = MOUSE_ALL_UP;
+
+ switch (mouse_type = ((minor(dev) & 0xf8) >> 3)) {
+ case MICROSOFT_MOUSE7:
+ mousebufsize = 3;
+ serial_mouse_open(dev);
+ init_mouse_hw(dev&7, LC7);
+ break;
+ case MICROSOFT_MOUSE:
+ mousebufsize = 3;
+ serial_mouse_open(dev);
+ init_mouse_hw(dev&7, LC8);
+ break;
+ case MOUSE_SYSTEM_MOUSE:
+ mousebufsize = 5;
+ serial_mouse_open(dev);
+ init_mouse_hw(dev&7, LC8);
+ break;
+ case LOGITECH_TRACKMAN:
+ mousebufsize = 3;
+ serial_mouse_open(dev);
+ init_mouse_hw(dev&7, LC7);
+ track_man[0] = comgetc(dev&7);
+ track_man[1] = comgetc(dev&7);
+ if (track_man[0] != 0x4d &&
+ track_man[1] != 0x33) {
+ printf("LOGITECH_TRACKMAN: NOT M3");
+ }
+ break;
+ case IBM_MOUSE:
+ mousebufsize = 3;
+ kd_mouse_open(dev, IBM_MOUSE_IRQ);
+ ibm_ps2_mouse_open(dev);
+ break;
+ case NO_MOUSE:
+ break;
+ }
+ mousebufindex = 0;
+ return(0);
+}
+
+void
+serial_mouse_open(dev_t dev)
+{
+ int unit = minor(dev) & 0x7;
+ int mouse_pic = cominfo[unit]->sysdep1;
+
+ spl_t s = splhi(); /* disable interrupts */
+
+ oldvect = ivect[mouse_pic];
+ ivect[mouse_pic] = mouseintr;
+
+ oldunit = iunit[mouse_pic];
+ iunit[mouse_pic] = unit;
+
+ /* XXX other arrays to init? */
+ splx(s); /* XXX - should come after init? */
+}
+
+int mouse_packets = 0;
+
+void
+kd_mouse_open(
+ dev_t dev,
+ int mouse_pic)
+{
+ spl_t s = splhi(); /* disable interrupts */
+
+ oldvect = ivect[mouse_pic];
+ ivect[mouse_pic] = kdintr;
+ unmask_irq(mouse_pic);
+ splx(s);
+}
+
+/*
+ * mouseclose - Disable interrupts on the serial port, reset driver flags,
+ * and restore the serial port interrupt vector.
+ */
+void
+mouseclose(
+ dev_t dev,
+ int flags)
+{
+ switch (mouse_type) {
+ case MICROSOFT_MOUSE:
+ case MICROSOFT_MOUSE7:
+ case MOUSE_SYSTEM_MOUSE:
+ case LOGITECH_TRACKMAN:
+ serial_mouse_close(dev, flags);
+ break;
+ case IBM_MOUSE:
+ ibm_ps2_mouse_close(dev);
+ kd_mouse_close(dev, IBM_MOUSE_IRQ);
+ {int i = 20000; for (;i--;); }
+ kd_mouse_drain();
+ break;
+ case NO_MOUSE:
+ break;
+ }
+
+ kdq_reset(&mouse_queue); /* paranoia */
+ mouse_in_use = FALSE;
+}
+
+/*ARGSUSED*/
+void
+serial_mouse_close(
+ dev_t dev,
+ int flags)
+{
+ spl_t o_pri = splhi(); /* mutex with open() */
+ int unit = minor(dev) & 0x7;
+ int mouse_pic = cominfo[unit]->sysdep1;
+ unsigned short base_addr = cominfo[unit]->address;
+
+ assert(ivect[mouse_pic] == mouseintr);
+ outb(base_addr + RIE, 0); /* disable serial port */
+ outb(base_addr + RMC, 0); /* no rts */
+ ivect[mouse_pic] = oldvect;
+ iunit[mouse_pic] = oldunit;
+
+ (void)splx(o_pri);
+}
+
+void
+kd_mouse_close(
+ dev_t dev,
+ int mouse_pic)
+{
+ spl_t s = splhi();
+
+ mask_irq(mouse_pic);
+ ivect[mouse_pic] = oldvect;
+ splx(s);
+}
+
+io_return_t mousegetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data, /* pointer to OUT array */
+ mach_msg_type_number_t *count) /* OUT */
+{
+ switch (flavor) {
+ case DEV_GET_SIZE:
+ data[DEV_GET_SIZE_DEVICE_SIZE] = 0;
+ data[DEV_GET_SIZE_RECORD_SIZE] = sizeof(kd_event);
+ *count = DEV_GET_SIZE_COUNT;
+ break;
+ default:
+ return D_INVALID_OPERATION;
+ }
+ return D_SUCCESS;
+}
+
+
+/*
+ * mouseread - dequeue and return any queued events.
+ */
+int
+mouseread(
+ dev_t dev,
+ io_req_t ior)
+{
+ int err, count;
+ spl_t s;
+
+ /* Check if IO_COUNT is a multiple of the record size. */
+ if (ior->io_count % sizeof(kd_event) != 0)
+ return D_INVALID_SIZE;
+
+ err = device_read_alloc(ior, (vm_size_t)ior->io_count);
+ if (err != KERN_SUCCESS)
+ return (err);
+
+ s = SPLKD();
+ if (kdq_empty(&mouse_queue)) {
+ if (ior->io_mode & D_NOWAIT) {
+ splx(s);
+ return (D_WOULD_BLOCK);
+ }
+ ior->io_done = mouse_read_done;
+ enqueue_tail(&mouse_read_queue, (queue_entry_t)ior);
+ splx(s);
+ return (D_IO_QUEUED);
+ }
+ count = 0;
+ while (!kdq_empty(&mouse_queue) && count < ior->io_count) {
+ kd_event *ev;
+
+ ev = kdq_get(&mouse_queue);
+ *(kd_event *)(&ior->io_data[count]) = *ev;
+ count += sizeof(kd_event);
+ }
+ splx(s);
+ ior->io_residual = ior->io_count - count;
+ return (D_SUCCESS);
+}
+
+boolean_t mouse_read_done(io_req_t ior)
+{
+ int count;
+ spl_t s;
+
+ s = SPLKD();
+ if (kdq_empty(&mouse_queue)) {
+ ior->io_done = mouse_read_done;
+ enqueue_tail(&mouse_read_queue, (queue_entry_t)ior);
+ splx(s);
+ return (FALSE);
+ }
+
+ count = 0;
+ while (!kdq_empty(&mouse_queue) && count < ior->io_count) {
+ kd_event *ev;
+
+ ev = kdq_get(&mouse_queue);
+ *(kd_event *)(&ior->io_data[count]) = *ev;
+ count += sizeof(kd_event);
+ }
+ splx(s);
+
+ ior->io_residual = ior->io_count - count;
+ ds_read_done(ior);
+
+ return (TRUE);
+}
+
+
+
+/*
+ * mouseintr - Get a byte and pass it up for handling. Called at SPLKD.
+ */
+void
+mouseintr(int unit)
+{
+ unsigned short base_addr = cominfo[unit]->address;
+ unsigned char id, ls;
+
+ /* get reason for interrupt and line status */
+ id = inb(base_addr + RID);
+ ls = inb(base_addr + RLS);
+
+ /* handle status changes */
+ if (id == IDLS) {
+ if (ls & LSDR) {
+ inb(base_addr + RDAT); /* flush bad character */
+ }
+ return; /* ignore status change */
+ }
+
+ if (id & IDRD) {
+ mouse_handle_byte((u_char)(inb(base_addr + RDAT) & 0xff));
+ }
+}
+
+
+/*
+ * handle_byte - Accumulate bytes until we have an entire packet.
+ * If the mouse has moved or any of the buttons have changed state (up
+ * or down), enqueue the corresponding events.
+ * Called at SPLKD.
+ * XXX - magic numbers.
+ */
+int show_mouse_byte = 0;
+/*
+ X down; middle down; middle up; X up 50 0 0; 50 0 0 22; 50 0 0 02; 40 0 0
+ X down; middle down; X up; middle up 50 0 0; 50 0 0 22; 40 0 0 22; 40 0 0 2
+ *
+ * The trick here is that all the while the middle button is down you get 4 byte
+ * packets with the last byte 0x22. When the middle button goes up you get a
+ * last packet with 0x02.
+ */
+int lastgitech = 0x40; /* figure whether the first 3 bytes imply */
+ /* its time to expect a fourth */
+int fourthgitech = 0; /* look for the 4th byte; we must process it */
+int middlegitech = 0; /* what should the middle button be */
+
+static u_char mousebuf[MOUSEBUFSIZE]; /* 5-byte packet from mouse */
+
+void
+mouse_handle_byte(u_char ch)
+{
+ if (show_mouse_byte) {
+ printf("%x(%c) ", ch, ch);
+ }
+
+ if (mouse_char_cmd) {
+ /*
+ * Mouse character is response to command
+ */
+ if (mousebufindex < mousebufsize)
+ mousebuf[mousebufindex++] = ch;
+ if (mouse_char_wanted) {
+ mouse_char_wanted = FALSE;
+ wakeup((vm_offset_t)&mousebuf);
+ }
+ return;
+ }
+
+ if (mousebufindex == 0) {
+ switch (mouse_type) {
+ case MICROSOFT_MOUSE7:
+ if ((ch & 0x40) != 0x40)
+ return;
+ break;
+ case MICROSOFT_MOUSE:
+ if ((ch & 0xc0) != 0xc0)
+ return;
+ break;
+ case MOUSE_SYSTEM_MOUSE:
+ if ((ch & 0xf8) != 0x80)
+ return;
+ break;
+ case LOGITECH_TRACKMAN:
+ if (fourthgitech == 1) {
+ fourthgitech = 0;
+ if (ch & 0xf0)
+ middlegitech = 0x4;
+ else
+ middlegitech = 0x0;
+ mouse_packet_microsoft_mouse(mousebuf);
+ return;
+ } else if ((ch & 0xc0) != 0x40)
+ return;
+ break;
+ case IBM_MOUSE:
+ break;
+ }
+ }
+
+ mousebuf[mousebufindex++] = ch;
+ if (mousebufindex < mousebufsize)
+ return;
+
+ /* got a packet */
+ mousebufindex = 0;
+
+ switch (mouse_type) {
+ case MICROSOFT_MOUSE7:
+ case MICROSOFT_MOUSE:
+ mouse_packet_microsoft_mouse(mousebuf);
+ break;
+ case MOUSE_SYSTEM_MOUSE:
+ mouse_packet_mouse_system_mouse(mousebuf);
+ break;
+ case LOGITECH_TRACKMAN:
+ if ( mousebuf[1] || mousebuf[2] ||
+ mousebuf[0] != lastgitech) {
+ mouse_packet_microsoft_mouse(mousebuf);
+ lastgitech = mousebuf[0] & 0xf0;
+ } else {
+ fourthgitech = 1;
+ }
+ break;
+ case IBM_MOUSE:
+ mouse_packet_ibm_ps2_mouse(mousebuf);
+ break;
+ }
+}
+
+void
+mouse_packet_mouse_system_mouse(u_char mousebuf[MOUSEBUFSIZE])
+{
+ u_char buttons, buttonchanges;
+ struct mouse_motion moved;
+
+ buttons = mousebuf[0] & 0x7; /* get current state of buttons */
+ buttonchanges = buttons ^ lastbuttons;
+ moved.mm_deltaX = (char)mousebuf[1] + (char)mousebuf[3];
+ moved.mm_deltaY = (char)mousebuf[2] + (char)mousebuf[4];
+
+ if (moved.mm_deltaX != 0 || moved.mm_deltaY != 0)
+ mouse_moved(moved);
+
+ if (buttonchanges != 0) {
+ lastbuttons = buttons;
+ if (buttonchanges & 1)
+ mouse_button(MOUSE_RIGHT, buttons & 1);
+ if (buttonchanges & 2)
+ mouse_button(MOUSE_MIDDLE, (buttons & 2) >> 1);
+ if (buttonchanges & 4)
+ mouse_button(MOUSE_LEFT, (buttons & 4) >> 2);
+ }
+}
+
+/* same as above for microsoft mouse */
+/*
+ * 3 byte microsoft format used
+ *
+ * 7 6 5 4 3 2 1 0
+ * 1 1 L R Y7 Y6 X7 X6
+ * 1 0 X5 X4 X3 X3 X1 X0
+ * 1 0 Y5 Y4 Y3 Y2 Y1 Y0
+ *
+ */
+void
+mouse_packet_microsoft_mouse(u_char mousebuf[MOUSEBUFSIZE])
+{
+ u_char buttons, buttonchanges;
+ struct mouse_motion moved;
+
+ buttons = ((mousebuf[0] & 0x30) >> 4);
+ buttons |= middlegitech;
+ /* get current state of buttons */
+#ifdef gross_hack
+ if (buttons == 0x03) /* both buttons down */
+ buttons = 0x04;
+#endif /* gross_hack */
+ buttons = (~buttons) & 0x07; /* convert to not pressed */
+
+ buttonchanges = buttons ^ lastbuttons;
+ moved.mm_deltaX = ((mousebuf[0] & 0x03) << 6) | (mousebuf[1] & 0x3F);
+ moved.mm_deltaY = ((mousebuf[0] & 0x0c) << 4) | (mousebuf[2] & 0x3F);
+ if (moved.mm_deltaX & 0x80) /* negative, in fact */
+ moved.mm_deltaX = moved.mm_deltaX - 0x100;
+ if (moved.mm_deltaY & 0x80) /* negative, in fact */
+ moved.mm_deltaY = moved.mm_deltaY - 0x100;
+ /* and finally the Y orientation is different for the microsoft mouse */
+ moved.mm_deltaY = -moved.mm_deltaY;
+
+ if (moved.mm_deltaX != 0 || moved.mm_deltaY != 0)
+ mouse_moved(moved);
+
+ if (buttonchanges != 0) {
+ lastbuttons = buttons;
+ if (buttonchanges & 1)
+ mouse_button(MOUSE_RIGHT, (buttons & 1) ?
+ MOUSE_UP : MOUSE_DOWN);
+ if (buttonchanges & 2)
+ mouse_button(MOUSE_LEFT, (buttons & 2) ?
+ MOUSE_UP : MOUSE_DOWN);
+ if (buttonchanges & 4)
+ mouse_button(MOUSE_MIDDLE, (buttons & 4) ?
+ MOUSE_UP : MOUSE_DOWN);
+ }
+}
+
+/*
+ * AUX device (PS2) open/close
+ */
+
+/*
+ * Write character to mouse. Called at spltty.
+ */
+static void kd_mouse_write(
+ unsigned char ch)
+{
+ while (inb(K_STATUS) & K_IBUF_FUL)
+ continue; /* wait for 'input' port empty */
+ outb(K_CMD, 0xd4); /* send next character to mouse */
+
+ while (inb(K_STATUS) & K_IBUF_FUL)
+ continue; /* wait for 'input' port empty */
+ outb(K_RDWR, ch); /* send command to mouse */
+}
+
+/*
+ * Read next character from mouse, waiting for interrupt
+ * to deliver it. Called at spltty.
+ */
+static int kd_mouse_read(void)
+{
+ int ch;
+
+ if (mouse_char_index >= mousebufsize)
+ return -1;
+
+ while (mousebufindex <= mouse_char_index) {
+ mouse_char_wanted = TRUE;
+ assert_wait((event_t) &mousebuf, FALSE);
+ /* We are at tty SPL level, interrupts can not happen between
+ * assert_wait and thread_block. */
+ thread_block((void (*)()) 0);
+ }
+
+ ch = mousebuf[mouse_char_index++];
+
+ return ch;
+}
+
+/*
+ * Prepare buffer for receiving next packet from mouse.
+ */
+static void kd_mouse_read_reset(void)
+{
+ mousebufindex = 0;
+ mouse_char_index = 0;
+}
+
+void
+ibm_ps2_mouse_open(dev_t dev)
+{
+ spl_t s = spltty();
+
+ lastbuttons = 0;
+ mouse_char_cmd = TRUE; /* responses are to commands */
+
+ kd_sendcmd(0xa8); /* enable mouse in kbd */
+
+ kd_cmdreg_write(0x47); /* allow mouse interrupts */
+ /* magic number for ibm? */
+
+ kd_mouse_read_reset();
+ kd_mouse_write(0xff); /* reset mouse */
+ if (kd_mouse_read() != 0xfa) {
+ splx(s);
+ return; /* need ACK */
+ }
+
+ (void) kd_mouse_read(); /* discard 2-character mouse ID */
+ (void) kd_mouse_read();
+
+ kd_mouse_read_reset();
+ kd_mouse_write(0xea); /* set stream mode */
+ if (kd_mouse_read() != 0xfa) {
+ splx(s);
+ return; /* need ACK */
+ }
+
+ kd_mouse_read_reset();
+ kd_mouse_write(0xf4); /* enable */
+ if (kd_mouse_read() != 0xfa) {
+ splx(s);
+ return; /* need ACK */
+ }
+
+ kd_mouse_read_reset();
+ mouse_char_cmd = FALSE; /* now we get mouse packets */
+
+ splx(s);
+}
+
+void
+ibm_ps2_mouse_close(dev_t dev)
+{
+ spl_t s = spltty();
+
+ mouse_char_cmd = TRUE; /* responses are to commands */
+
+ kd_mouse_read_reset();
+ kd_mouse_write(0xff); /* reset mouse */
+ if (kd_mouse_read() == 0xfa) {
+ /* got ACK: discard 2-char mouse ID */
+ (void) kd_mouse_read();
+ (void) kd_mouse_read();
+ }
+
+ kd_sendcmd(0xa7); /* disable mouse in kbd */
+ kd_cmdreg_write(0x65); /* disallow mouse interrupts */
+ /* magic number for ibm? */
+
+ splx(s);
+}
+
+/*
+ * 3 byte ibm ps2 format used
+ *
+ * 7 6 5 4 3 2 1 0
+ * YO XO YS XS 1 M R L
+ * X7 X6 X5 X4 X3 X3 X1 X0
+ * Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+ *
+ */
+void
+mouse_packet_ibm_ps2_mouse(u_char mousebuf[MOUSEBUFSIZE])
+{
+ u_char buttons, buttonchanges;
+ struct mouse_motion moved;
+
+ buttons = mousebuf[0] & 0x7; /* get current state of buttons */
+ buttonchanges = buttons ^ lastbuttons;
+ moved.mm_deltaX = ((mousebuf[0]&0x10) ? 0xffffff00 : 0 ) | (u_char)mousebuf[1];
+ moved.mm_deltaY = ((mousebuf[0]&0x20) ? 0xffffff00 : 0 ) | (u_char)mousebuf[2];
+ if (mouse_packets) {
+ printf("(%x:%x:%x)", mousebuf[0], mousebuf[1], mousebuf[2]);
+ return;
+ }
+
+ if (moved.mm_deltaX != 0 || moved.mm_deltaY != 0)
+ mouse_moved(moved);
+
+ if (buttonchanges != 0) {
+ lastbuttons = buttons;
+ if (buttonchanges & 1)
+ mouse_button(MOUSE_LEFT, !(buttons & 1));
+ if (buttonchanges & 2)
+ mouse_button(MOUSE_RIGHT, !((buttons & 2) >> 1));
+ if (buttonchanges & 4)
+ mouse_button(MOUSE_MIDDLE, !((buttons & 4) >> 2));
+ }
+}
+
+/*
+ * Enqueue a mouse-motion event. Called at SPLKD.
+ */
+void
+mouse_moved(struct mouse_motion where)
+{
+ kd_event ev;
+
+ ev.type = MOUSE_MOTION;
+ /* Not used but we set it to avoid garbage */
+ ev.unused_time.seconds = 0;
+ ev.unused_time.microseconds = 0;
+ ev.value.mmotion = where;
+ mouse_enqueue(&ev);
+}
+
+/*
+ * Enqueue an event for mouse button press or release. Called at SPLKD.
+ */
+void
+mouse_button(
+ kev_type which,
+ u_char direction)
+{
+ kd_event ev;
+
+ ev.type = which;
+ ev.value.up = (direction == MOUSE_UP) ? TRUE : FALSE;
+ /* Not used but we set it to avoid garbage */
+ ev.unused_time.seconds = 0;
+ ev.unused_time.microseconds = 0;
+ mouse_enqueue(&ev);
+}
+
+/*
+ * mouse_enqueue - enqueue an event and wake up selecting processes, if
+ * any. Called at SPLKD.
+ */
+
+void
+mouse_enqueue(kd_event *ev)
+{
+ if (kdq_full(&mouse_queue))
+ printf_once("mouse: queue full\n");
+ else
+ kdq_put(&mouse_queue, ev);
+
+ {
+ io_req_t ior;
+ while ((ior = (io_req_t)dequeue_head(&mouse_read_queue)) != 0)
+ iodone(ior);
+ }
+}
diff --git a/i386/i386at/kd_mouse.h b/i386/i386at/kd_mouse.h
new file mode 100644
index 0000000..a9fb128
--- /dev/null
+++ b/i386/i386at/kd_mouse.h
@@ -0,0 +1,72 @@
+/*
+ * Mouse event handlers
+ * Copyright (C) 2006 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, 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, write to the Free Software
+ * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Barry deFreese.
+ */
+/*
+ * Mouse event handling functions.
+ *
+ */
+
+#ifndef _KD_MOUSE_H_
+#define _KD_MOUSE_H_
+
+#include <sys/types.h>
+
+#define MOUSEBUFSIZE 5 /* num bytes def'd by protocol */
+
+extern void mouse_button (kev_type which, u_char direction);
+
+extern void mouse_enqueue (kd_event *ev);
+
+extern void mouse_moved (struct mouse_motion where);
+
+extern void mouse_handle_byte (u_char ch);
+
+extern void serial_mouse_open (dev_t dev);
+
+extern void serial_mouse_close (dev_t dev, int flags);
+
+extern void kd_mouse_open (dev_t dev, int mouse_pic);
+
+extern void kd_mouse_close (dev_t dev, int mouse_pic);
+
+extern void ibm_ps2_mouse_open (dev_t dev);
+
+extern void ibm_ps2_mouse_close (dev_t dev);
+
+extern void mouse_packet_microsoft_mouse (u_char mousebuf[MOUSEBUFSIZE]);
+
+extern void mouse_packet_mouse_system_mouse (u_char mousebuf[MOUSEBUFSIZE]);
+
+extern void mouse_packet_ibm_ps2_mouse (u_char mousebuf[MOUSEBUFSIZE]);
+
+extern int mouseopen(dev_t dev, int flags, io_req_t ior);
+extern void mouseclose(dev_t dev, int flags);
+extern int mouseread(dev_t dev, io_req_t ior);
+
+extern io_return_t mousegetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t *count);
+
+void mouseintr(int unit);
+boolean_t mouse_read_done(io_req_t ior);
+
+#endif /* _KD_MOUSE_H_ */
diff --git a/i386/i386at/kd_queue.c b/i386/i386at/kd_queue.c
new file mode 100644
index 0000000..ab399cd
--- /dev/null
+++ b/i386/i386at/kd_queue.c
@@ -0,0 +1,109 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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: kd_queue.c
+ Description: Event queue code for keyboard/display (and mouse) driver.
+
+ $ Header: $
+
+ Copyright Ing. C. Olivetti & C. S.p.A. 1989.
+ All rights reserved.
+********************************************************************** */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+
+#include <i386at/kd_queue.h>
+
+/*
+ * Notice that when adding an entry to the queue, the caller provides
+ * its own storage, which is copied into the queue. However, when
+ * removing an entry from the queue, the caller is given a pointer to a
+ * queue element. This means that the caller must either process the
+ * element or copy it into its own storage before unlocking the queue.
+ *
+ * These routines should be called only at a protected SPL.
+ */
+
+#define q_next(index) (((index)+1) % KDQSIZE)
+
+boolean_t
+kdq_empty(const kd_event_queue *q)
+{
+ return(q->firstfree == q->firstout);
+}
+
+boolean_t
+kdq_full(const kd_event_queue *q)
+{
+ return(q_next(q->firstfree) == q->firstout);
+}
+
+void
+kdq_put(kd_event_queue *q, kd_event *ev)
+{
+ kd_event *qp = q->events + q->firstfree;
+
+ qp->type = ev->type;
+ qp->unused_time = ev->unused_time;
+ qp->value = ev->value;
+ q->firstfree = q_next(q->firstfree);
+}
+
+kd_event *
+kdq_get(kd_event_queue *q)
+{
+ kd_event *result = q->events + q->firstout;
+
+ q->firstout = q_next(q->firstout);
+ return(result);
+}
+
+void
+kdq_reset(kd_event_queue *q)
+{
+ q->firstout = q->firstfree = 0;
+}
diff --git a/i386/i386at/kd_queue.h b/i386/i386at/kd_queue.h
new file mode 100644
index 0000000..702efe8
--- /dev/null
+++ b/i386/i386at/kd_queue.h
@@ -0,0 +1,86 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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: kd_queue.h
+ Description: definitions for keybd/display Event queue
+
+ $ Header: $
+
+ Copyright Ing. C. Olivetti & C. S.p.A. 1989.
+ All rights reserved.
+********************************************************************** */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * Definitions for keyboard/mouse events.
+ *
+ * The keyboard and mouse can be read as a stream of events. The event
+ * definition is the same in both cases, but only keyboard events will
+ * be generated by /dev/kbd, and only mouse events will be generated by
+ * /dev/mouse.
+ */
+
+#ifndef _KD_QUEUE_H_
+#define _KD_QUEUE_H_
+
+#include <mach/std_types.h>
+#include <i386at/kd.h>
+
+#define KDQSIZE 100 /* is this a good size? */
+
+typedef struct {
+ kd_event events[KDQSIZE];
+ int firstfree, firstout;
+} kd_event_queue;
+
+extern void kdq_put(kd_event_queue *, kd_event *);
+extern void kdq_reset(kd_event_queue *);
+extern boolean_t kdq_empty(const kd_event_queue *);
+extern boolean_t kdq_full(const kd_event_queue *);
+extern kd_event *kdq_get(kd_event_queue *);
+
+#endif /* _KD_QUEUE_H_ */
diff --git a/i386/i386at/kdasm.S b/i386/i386at/kdasm.S
new file mode 100644
index 0000000..fd0e1c8
--- /dev/null
+++ b/i386/i386at/kdasm.S
@@ -0,0 +1,145 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+/*
+ * Some inline code to speed up major block copies to and from the
+ * screen buffer.
+ *
+ * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989.
+ * All rights reserved.
+ *
+ * orc!eugene 28 Oct 1988
+ *
+ */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/* $ Header: $ */
+
+
+#include <mach/machine/asm.h>
+
+/*
+ * Function: kd_slmwd()
+ *
+ * This function "slams" a word (char/attr) into the screen memory using
+ * a block fill operation on the 386.
+ *
+ */
+
+#define start B_ARG0
+#define count B_ARG1
+#define value B_ARG2
+
+ENTRY(kd_slmwd)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %edi
+
+ movl start, %edi
+ movl count, %ecx
+ movw value, %ax
+ cld
+ rep
+ stosw
+
+ popl %edi
+ leave
+ ret
+#undef start
+#undef count
+#undef value
+
+/*
+ * "slam up"
+ */
+
+#define from B_ARG0
+#define to B_ARG1
+#define count B_ARG2
+ENTRY(kd_slmscu)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+
+ movl from, %esi
+ movl to, %edi
+ movl count, %ecx
+ cmpl %edi, %esi
+ cld
+ rep
+ movsw
+
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+/*
+ * "slam down"
+ */
+ENTRY(kd_slmscd)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+
+ movl from, %esi
+ movl to, %edi
+ movl count, %ecx
+ cmpl %edi, %esi
+ std
+ rep
+ movsw
+ cld
+
+ popl %edi
+ popl %esi
+ leave
+ ret
+#undef from
+#undef to
+#undef count
diff --git a/i386/i386at/kdsoft.h b/i386/i386at/kdsoft.h
new file mode 100644
index 0000000..79bfdb0
--- /dev/null
+++ b/i386/i386at/kdsoft.h
@@ -0,0 +1,209 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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: kdsoft.h
+ Description: Software structures for keyboard/display driver, shared with
+ drivers for specific graphics cards.
+
+ $ Header: $
+
+ Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989.
+ All rights reserved.
+********************************************************************** */
+
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef _KDSOFT_H_
+#define _KDSOFT_H_
+
+/*
+ * Globals used for both character-based controllers and bitmap-based
+ * controllers.
+ */
+typedef short csrpos_t; /* cursor position, ONE_SPACE bytes per char */
+
+extern u_char *vid_start; /* VM start of video RAM or frame buffer */
+extern csrpos_t kd_curpos; /* should be set only by kd_setpos */
+extern short kd_lines; /* num lines in tty display */
+extern short kd_cols;
+extern char kd_attr; /* current character attribute */
+
+
+/*
+ * Globals used only for bitmap-based controllers.
+ * XXX - probably needs reworking for color.
+ */
+
+/*
+ * This driver handles two types of graphics cards. The first type
+ * (e.g., EGA, CGA), treats the screen as a page of characters and
+ * has a hardware cursor. The second type (e.g., the Blit) treats the
+ * screen as a bitmap. A hardware cursor may be present, but it is
+ * ignored in favor of a software cursor.
+ *
+ *
+ * Most of the driver uses the following abstraction for the display:
+ *
+ * The cursor position is simply an index into a (logical) linear char
+ * array that wraps around at the end of each line. Each character
+ * takes up ONE_SPACE bytes. Values in [0..ONE_PAGE) are positions in
+ * the displayed page. Values < 0 and >= ONE_PAGE are off the page
+ * and require some scrolling to put the cursor back on the page.
+ *
+ * The kd_dxxx routines handle the conversion from this abstraction to
+ * what the hardware requires.
+ *
+ * (*kd_dput)(pos, ch, chattr)
+ * csrpos_t pos;
+ * char ch, chattr;
+ * Displays a character at "pos", where "ch" = the character to
+ * be displayed and "chattr" is its attribute byte.
+ *
+ * (*kd_dmvup)(from, to, count)
+ * csrpos_t from, to;
+ * int count;
+ * Does a (relatively) fast block transfer of characters upward.
+ * "count" is the number of character positions (not bytes) to move.
+ * "from" is the character position to start moving from (at the start
+ * of the block to be moved). "to" is the character position to start
+ * moving to.
+ *
+ * (*kd_dmvdown)(from, to, count)
+ * csrpos_t from, to;
+ * int count;
+ * "count" is the number of character positions (not bytes) to move.
+ * "from" is the character position to start moving from (at the end
+ * of the block to be moved). "to" is the character position to
+ * start moving to.
+ *
+ * (*kd_dclear)(to, count, chattr)
+ * csrpos_t, to;
+ * int count;
+ * char chattr;
+ * Erases "count" character positions, starting with "to".
+ *
+ * (*kd_dsetcursor)(pos)
+ * Sets kd_curpos and moves the displayed cursor to track it. "pos"
+ * should be in the range [0..ONE_PAGE).
+ *
+ * (*kd_dreset)()
+ * In some cases, the boot program expects the display to be in a
+ * particular state, and doing a soft reset (i.e.,
+ * software-controlled reboot) doesn't put it into that state. For
+ * these cases, the machine-specific driver should provide a "reset"
+ * procedure, which will be called just before the kd code causes the
+ * system to reboot.
+ */
+
+extern void bmpput(csrpos_t, char, char);
+extern void bmpmvup(csrpos_t, csrpos_t, int);
+extern void bmpmvdown(csrpos_t, csrpos_t, int);
+extern void bmpclear(csrpos_t, int, char);
+extern void bmpsetcursor(csrpos_t);
+
+extern void (*kd_dput)(csrpos_t, char, char); /* put attributed char */
+extern void (*kd_dmvup)(csrpos_t, csrpos_t, int); /* block move up */
+extern void (*kd_dmvdown)(csrpos_t, csrpos_t, int); /* block move down */
+extern void (*kd_dclear)(csrpos_t, int, char); /* block clear */
+extern void (*kd_dsetcursor)(csrpos_t); /* set cursor position on displayed page */
+extern void (*kd_dreset)(void); /* prepare for reboot */
+
+
+/*
+ * The following font layout is assumed:
+ *
+ * The top scan line of all the characters comes first. Then the
+ * second scan line, then the third, etc.
+ *
+ * ------ ... ---------|-----N--------|-------------- ... -----------
+ * ------ ... ---------|-----N--------|-------------- ... -----------
+ * .
+ * .
+ * .
+ * ------ ... ---------|-----N--------|-------------- ... -----------
+ *
+ * In the picture, each line is a scan line from the font. Each scan
+ * line is stored in memory immediately after the previous one. The
+ * bits between the vertical lines are the bits for a single character
+ * (e.g., the letter "N").
+ * There are "char_height" scan lines. Each character is "char_width"
+ * bits wide. We make the simplifying assumption that characters are
+ * on byte boundaries. (We also assume that a byte is 8 bits.)
+ */
+
+extern u_char *font_start; /* starting addr of font */
+
+extern short fb_width; /* bits in frame buffer scan line */
+extern short fb_height; /* scan lines in frame buffer*/
+extern short char_width; /* bit width of 1 char */
+extern short char_height; /* bit height of 1 char */
+extern short chars_in_font;
+extern short cursor_height; /* bit height of cursor */
+ /* char_height + cursor_height = line_height */
+
+extern u_char char_black; /* 8 black (off) bits */
+extern u_char char_white; /* 8 white (on) bits */
+
+
+/*
+ * The tty emulation does not usually require the entire frame buffer.
+ * (xstart, ystart) is the bit address for the upper left corner of the
+ * tty "screen".
+ */
+
+extern short xstart, ystart;
+
+
+/*
+ * Accelerators for bitmap displays.
+ */
+
+extern short char_byte_width; /* char_width/8 */
+extern short fb_byte_width; /* fb_width/8 */
+extern short font_byte_width; /* num bytes in 1 scan line of font */
+
+#endif /* _KDSOFT_H_ */
diff --git a/i386/i386at/lpr.c b/i386/i386at/lpr.c
new file mode 100644
index 0000000..f8d42f3
--- /dev/null
+++ b/i386/i386at/lpr.c
@@ -0,0 +1,285 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1990 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.
+ */
+/*
+ * Parallel port printer driver v1.0
+ * All rights reserved.
+ */
+
+#if NLPR > 0
+
+#include <mach/std_types.h>
+#include <sys/types.h>
+#include <kern/printf.h>
+#include <kern/mach_clock.h>
+#include <device/conf.h>
+#include <device/device_types.h>
+#include <device/tty.h>
+#include <device/io_req.h>
+
+#include <i386/ipl.h>
+#include <i386/pio.h>
+#include <chips/busses.h>
+#include <i386at/autoconf.h>
+#include <i386at/lpr.h>
+
+/*
+ * Driver information for auto-configuration stuff.
+ */
+
+struct bus_device *lprinfo[NLPR]; /* ??? */
+
+static vm_offset_t lpr_std[NLPR] = { 0 };
+static struct bus_device *lpr_info[NLPR];
+struct bus_driver lprdriver = {
+ lprprobe, 0, lprattach, 0, lpr_std, "lpr", lpr_info, 0, 0, 0};
+
+struct tty lpr_tty[NLPR];
+
+int lpr_alive[NLPR];
+
+int
+lprprobe(vm_offset_t port, struct bus_ctlr *dev)
+{
+ u_short addr = (u_short) dev->address;
+ int unit = dev->unit;
+ int ret;
+
+ if ((unit < 0) || (unit >= NLPR)) {
+ printf("com %d out of range\n", unit);
+ return(0);
+ }
+
+ outb(INTR_ENAB(addr),0x07);
+ outb(DATA(addr),0xaa);
+ ret = inb(DATA(addr)) == 0xaa;
+ if (ret) {
+ if (lpr_alive[unit]) {
+ printf("lpr: Multiple alive entries for unit %d.\n", unit);
+ printf("lpr: Ignoring entry with address = %x .\n", addr);
+ ret = 0;
+ } else
+ lpr_alive[unit]++;
+ }
+ return(ret);
+}
+
+void lprattach(struct bus_device *dev)
+{
+ u_char unit = dev->unit;
+ u_short addr = (u_short) dev->address;
+
+ if (unit >= NLPR) {
+ printf(", disabled by NLPR configuration\n");
+ return;
+ }
+
+ take_dev_irq(dev);
+ printf(", port = %zx, spl = %zd, pic = %d.",
+ dev->address, dev->sysdep, dev->sysdep1);
+ lprinfo[unit] = dev;
+
+ outb(INTR_ENAB(addr), inb(INTR_ENAB(addr)) & 0x0f);
+
+ return;
+}
+
+int
+lpropen(dev_t dev, int flag, io_req_t ior)
+{
+ int unit = minor(dev);
+ struct bus_device *isai;
+ struct tty *tp;
+ u_short addr;
+
+ if (unit >= NLPR)
+ return D_NO_SUCH_DEVICE;
+
+ isai = lprinfo[unit];
+ if (isai == NULL || !isai->alive)
+ return D_NO_SUCH_DEVICE;
+
+ tp = &lpr_tty[unit];
+ addr = (u_short) isai->address;
+ tp->t_dev = dev;
+ tp->t_addr = (void*) (natural_t) addr;
+ tp->t_oproc = lprstart;
+ tp->t_state |= TS_WOPEN;
+ tp->t_stop = lprstop;
+ tp->t_getstat = lprgetstat;
+ tp->t_setstat = lprsetstat;
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ ttychars(tp);
+ outb(INTR_ENAB(addr), inb(INTR_ENAB(addr)) | 0x10);
+ tp->t_state |= TS_CARR_ON;
+ return (char_open(dev, tp, flag, ior));
+}
+
+void
+lprclose(dev_t dev, int flag)
+{
+int unit = minor(dev);
+struct tty *tp = &lpr_tty[unit];
+u_short addr = (u_short) lprinfo[unit]->address;
+
+ ttyclose(tp);
+ if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) {
+ outb(INTR_ENAB(addr), inb(INTR_ENAB(addr)) & 0x0f);
+ tp->t_state &= ~TS_BUSY;
+ }
+}
+
+int
+lprread(dev_t dev, io_req_t ior)
+{
+ return char_read(&lpr_tty[minor(dev)], ior);
+}
+
+int
+lprwrite(dev_t dev, io_req_t ior)
+{
+ return char_write(&lpr_tty[minor(dev)], ior);
+}
+
+int
+lprportdeath(dev_t dev, mach_port_t port)
+{
+ return (tty_portdeath(&lpr_tty[minor(dev)], (ipc_port_t)port));
+}
+
+io_return_t
+lprgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data, /* pointer to OUT array */
+ mach_msg_type_number_t *count /* out */
+ )
+{
+ io_return_t result = D_SUCCESS;
+ int unit = minor(dev);
+
+ switch (flavor) {
+ default:
+ result = tty_get_status(&lpr_tty[unit], flavor, data, count);
+ break;
+ }
+ return (result);
+}
+
+io_return_t
+lprsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count)
+{
+ io_return_t result = D_SUCCESS;
+ int unit = minor(dev);
+
+ switch (flavor) {
+ default:
+ result = tty_set_status(&lpr_tty[unit], flavor, data, count);
+/* if (result == D_SUCCESS && flavor == TTY_STATUS)
+ lprparam(unit);
+*/ return (result);
+ }
+ return (D_SUCCESS);
+}
+
+void lprintr(int unit)
+{
+ struct tty *tp = &lpr_tty[unit];
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_state&TS_FLUSH)
+ tp->t_state &=~TS_FLUSH;
+ tt_write_wakeup(tp);
+ lprstart(tp);
+}
+
+void lprstart(struct tty *tp)
+{
+ spl_t s = spltty();
+ u_short addr = (natural_t) tp->t_addr;
+ int status = inb(STATUS(addr));
+ int nch;
+
+ if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) {
+ splx(s);
+ return;
+ }
+
+ if (status & 0x20) {
+ printf("Printer out of paper!\n");
+ splx(s);
+ return;
+ }
+
+ if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
+ tt_write_wakeup(tp);
+ }
+ if (tp->t_outq.c_cc == 0) {
+ splx(s);
+ return;
+ }
+ nch = getc(&tp->t_outq);
+ if (nch == -1) {
+ splx(s);
+ return;
+ }
+ if ((tp->t_flags & LITOUT) == 0 && (nch & 0200)) {
+ timeout((timer_func_t *)ttrstrt, (char *)tp, (nch & 0x7f) + 6);
+ tp->t_state |= TS_TIMEOUT;
+ return;
+ }
+ outb(DATA(addr), nch);
+ outb(INTR_ENAB(addr),inb(INTR_ENAB(addr)) | 0x01);
+ outb(INTR_ENAB(addr),inb(INTR_ENAB(addr)) & 0x1e);
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ return;
+}
+
+void
+lprstop(
+ struct tty *tp,
+ int flags)
+{
+ if ((tp->t_state & TS_BUSY) && (tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+}
+
+void
+lprpr_addr(unsigned short addr)
+{
+ printf("DATA(%x) %x, STATUS(%x) %x, INTR_ENAB(%x) %x\n",
+ DATA(addr), inb(DATA(addr)),
+ STATUS(addr), inb(STATUS(addr)),
+ INTR_ENAB(addr), inb(INTR_ENAB(addr)));
+}
+#endif /* NLPR */
diff --git a/i386/i386at/lpr.h b/i386/i386at/lpr.h
new file mode 100644
index 0000000..cab3016
--- /dev/null
+++ b/i386/i386at/lpr.h
@@ -0,0 +1,66 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 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.
+ */
+/*
+ * Parallel port printer driver v1.0
+ * All rights reserved.
+ */
+
+#ifndef _LPRREG_H_
+#define _LPRREG_H_
+
+#define DATA(addr) (addr + 0)
+#define STATUS(addr) (addr + 1)
+#define INTR_ENAB(addr) (addr + 2)
+
+extern void lprintr(int unit);
+int lprprobe(vm_offset_t port, struct bus_ctlr *dev);
+void lprstop(struct tty *tp, int flags);
+void lprstart(struct tty *tp);
+void lprattach(struct bus_device *dev);
+
+extern io_return_t
+lprgetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t *count);
+
+extern io_return_t
+lprsetstat(
+ dev_t dev,
+ dev_flavor_t flavor,
+ dev_status_t data,
+ mach_msg_type_number_t count);
+
+void lprpr_addr(unsigned short addr);
+
+extern int lpropen(dev_t dev, int flag, io_req_t ior);
+extern void lprclose(dev_t dev, int flag);
+extern int lprread(dev_t dev, io_req_t ior);
+extern int lprwrite(dev_t dev, io_req_t ior);
+extern int lprportdeath(dev_t dev, mach_port_t port);
+
+#endif /* _LPRREG_H_ */
diff --git a/i386/i386at/mem.c b/i386/i386at/mem.c
new file mode 100644
index 0000000..f46fc03
--- /dev/null
+++ b/i386/i386at/mem.c
@@ -0,0 +1,42 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+
+#include <device/io_req.h>
+#include <i386/model_dep.h>
+#include <i386at/biosmem.h>
+#include <i386at/mem.h>
+
+/* This provides access to any memory that is not main RAM */
+
+/*ARGSUSED*/
+vm_offset_t
+memmmap(dev_t dev, vm_offset_t off, vm_prot_t prot)
+{
+ if (biosmem_addr_available(off))
+ return -1;
+
+ return i386_btop(off);
+}
diff --git a/i386/i386at/mem.h b/i386/i386at/mem.h
new file mode 100644
index 0000000..a5b4aef
--- /dev/null
+++ b/i386/i386at/mem.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MEM_H_
+#define _MEM_H_
+
+extern vm_offset_t memmmap(dev_t dev, vm_offset_t off, vm_prot_t prot);
+
+#endif /* _MEM_H_ */
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;
+}
diff --git a/i386/i386at/model_dep.h b/i386/i386at/model_dep.h
new file mode 100644
index 0000000..3d5b664
--- /dev/null
+++ b/i386/i386at/model_dep.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MODEL_DEP_H_
+#define _MODEL_DEP_H_
+
+#include <i386/vm_param.h>
+#include <mach/vm_prot.h>
+
+/*
+ * Interrupt stack.
+ */
+extern vm_offset_t int_stack_top[NCPUS], int_stack_base[NCPUS];
+
+/* Check whether P points to the per-cpu interrupt stack. */
+#define ON_INT_STACK(P, CPU) (((P) & ~(INTSTACK_SIZE-1)) == int_stack_base[CPU])
+
+extern vm_offset_t timemmap(dev_t dev, vm_offset_t off, vm_prot_t prot);
+
+void inittodr(void);
+
+boolean_t init_alloc_aligned(vm_size_t size, vm_offset_t *addrp);
+
+#endif /* _MODEL_DEP_H_ */
diff --git a/i386/i386at/pic_isa.c b/i386/i386at/pic_isa.c
new file mode 100644
index 0000000..1e5ac10
--- /dev/null
+++ b/i386/i386at/pic_isa.c
@@ -0,0 +1,56 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 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.
+ */
+
+#include <sys/types.h>
+#include <i386/ipl.h>
+#include <i386/pic.h>
+#include <i386/fpu.h>
+#include <i386/hardclock.h>
+#include <i386at/kd.h>
+
+/* These interrupts are always present */
+
+interrupt_handler_fn ivect[NINTR] = {
+ /* 00 */ (interrupt_handler_fn)hardclock, /* always */
+ /* 01 */ kdintr, /* kdintr, ... */
+ /* 02 */ intnull,
+ /* 03 */ intnull, /* lnpoll, comintr, ... */
+
+ /* 04 */ intnull, /* comintr, ... */
+ /* 05 */ intnull, /* comintr, wtintr, ... */
+ /* 06 */ intnull, /* fdintr, ... */
+ /* 07 */ intnull, /* qdintr, ... */
+
+ /* 08 */ intnull,
+ /* 09 */ intnull, /* ether */
+ /* 10 */ intnull,
+ /* 11 */ intnull,
+
+ /* 12 */ intnull,
+ /* 13 */ fpintr, /* always */
+ /* 14 */ intnull, /* hdintr, ... */
+ /* 15 */ intnull, /* ??? */
+};
diff --git a/i386/i386at/rtc.c b/i386/i386at/rtc.c
new file mode 100644
index 0000000..1930beb
--- /dev/null
+++ b/i386/i386at/rtc.c
@@ -0,0 +1,242 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <sys/types.h>
+#include <kern/mach_clock.h>
+#include <kern/printf.h>
+#include <i386/machspl.h>
+#include <i386/pio.h>
+#include <i386at/rtc.h>
+
+/* time of day stored in RTC are currently between 1970 and 2070. Update that
+ * before 2070 please. */
+#define CENTURY_START 1970
+
+static boolean_t first_rtcopen_ever = TRUE;
+
+static void
+rtcinit(void)
+{
+ outb(RTC_ADDR, RTC_A);
+ outb(RTC_DATA, RTC_DIV2 | RTC_RATE6);
+ outb(RTC_ADDR, RTC_B);
+ outb(RTC_DATA, RTC_HM);
+}
+
+
+static int
+rtcget(struct rtc_st *st)
+{
+ unsigned char *regs = (unsigned char *)st;
+ if (first_rtcopen_ever) {
+ rtcinit();
+ first_rtcopen_ever = FALSE;
+ }
+ outb(RTC_ADDR, RTC_D);
+ if ((inb(RTC_DATA) & RTC_VRT) == 0) return(-1);
+ outb(RTC_ADDR, RTC_A);
+ while (inb(RTC_DATA) & RTC_UIP) /* busy wait */
+ outb(RTC_ADDR, RTC_A);
+ load_rtc(regs);
+ return(0);
+}
+
+static void
+rtcput(struct rtc_st *st)
+{
+ unsigned char *regs = (unsigned char *)st;
+ unsigned char x;
+
+ if (first_rtcopen_ever) {
+ rtcinit();
+ first_rtcopen_ever = FALSE;
+ }
+ outb(RTC_ADDR, RTC_B);
+ x = inb(RTC_DATA);
+ outb(RTC_ADDR, RTC_B);
+ outb(RTC_DATA, x | RTC_SET);
+ save_rtc(regs);
+ outb(RTC_ADDR, RTC_B);
+ outb(RTC_DATA, x & ~RTC_SET);
+}
+
+
+static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int
+yeartoday(int year)
+{
+ if (year%4)
+ /* Not divisible by 4, not bissextile */
+ return 365;
+
+ /* Divisible by 4 */
+ if (year % 100)
+ /* Not divisible by 100, bissextile */
+ return 366;
+
+ /* Divisible by 100 */
+ if (year % 400)
+ /* Not divisible by 400, not bissextile */
+ return 365;
+
+ /* Divisible by 400 */
+ /* Rules for 2000 and further have not been officially decided yet.
+ * 2000 was made bissextile. */
+ return 366;
+}
+
+static int
+hexdectodec(char n)
+{
+ return(((n>>4)&0x0F)*10 + (n&0x0F));
+}
+
+static char
+dectohexdec(int n)
+{
+ return((char)(((n/10)<<4)&0xF0) | ((n%10)&0x0F));
+}
+
+int
+readtodc(uint64_t *tp)
+{
+ struct rtc_st rtclk;
+ time_t n;
+ int sec, min, hr, dom, mon, yr;
+ int i, days = 0;
+ spl_t ospl;
+
+ ospl = splclock();
+ if (rtcget(&rtclk)) {
+ splx(ospl);
+ return(-1);
+ }
+ splx (ospl);
+
+ sec = hexdectodec(rtclk.rtc_sec);
+ min = hexdectodec(rtclk.rtc_min);
+ hr = hexdectodec(rtclk.rtc_hr);
+ dom = hexdectodec(rtclk.rtc_dom);
+ mon = hexdectodec(rtclk.rtc_mon);
+ yr = hexdectodec(rtclk.rtc_yr);
+ yr = (yr < CENTURY_START%100) ?
+ yr+CENTURY_START-CENTURY_START%100+100 :
+ yr+CENTURY_START-CENTURY_START%100;
+
+ if (yr >= CENTURY_START+90) {
+ printf("FIXME: we are approaching %u, update CENTURY_START\n", CENTURY_START);
+ }
+
+ printf("RTC time is %04u-%02u-%02u %02u:%02u:%02u\n", yr, mon, dom, hr, min, sec);
+
+ n = sec + 60 * min + 3600 * hr;
+ n += (dom - 1) * 3600 * 24;
+
+ if (yeartoday(yr) == 366)
+ month[1] = 29;
+ for (i = mon - 2; i >= 0; i--)
+ days += month[i];
+ month[1] = 28;
+ /* Epoch shall be 1970 January 1st */
+ for (i = 1970; i < yr; i++)
+ days += yeartoday(i);
+ n += days * 3600 * 24;
+
+
+ *tp = n;
+
+ return(0);
+}
+
+int
+writetodc(void)
+{
+ struct rtc_st rtclk;
+ time_t n;
+ int diff, i, j;
+ spl_t ospl;
+
+ ospl = splclock();
+ if (rtcget(&rtclk)) {
+ splx(ospl);
+ return(-1);
+ }
+ splx(ospl);
+
+ diff = 0;
+ n = (time.seconds - diff) % (3600 * 24); /* hrs+mins+secs */
+ rtclk.rtc_sec = dectohexdec(n%60);
+ n /= 60;
+ rtclk.rtc_min = dectohexdec(n%60);
+ rtclk.rtc_hr = dectohexdec(n/60);
+
+ n = (time.seconds - diff) / (3600 * 24); /* days */
+ rtclk.rtc_dow = (n + 4) % 7; /* 1/1/70 is Thursday */
+
+ /* Epoch shall be 1970 January 1st */
+ for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j))
+ n -= i;
+
+ rtclk.rtc_yr = dectohexdec(j % 100);
+
+ if (i == 366)
+ month[1] = 29;
+ for (i = 0; n >= month[i]; i++)
+ n -= month[i];
+ month[1] = 28;
+ rtclk.rtc_mon = dectohexdec(++i);
+
+ rtclk.rtc_dom = dectohexdec(++n);
+
+ ospl = splclock();
+ rtcput(&rtclk);
+ splx(ospl);
+
+ return(0);
+}
diff --git a/i386/i386at/rtc.h b/i386/i386at/rtc.h
new file mode 100644
index 0000000..5379722
--- /dev/null
+++ b/i386/i386at/rtc.h
@@ -0,0 +1,143 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 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.
+ */
+/*
+ Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef _RTC_H_
+#define _RTC_H_
+
+#define RTC_ADDR 0x70 /* I/O port address for register select */
+#define RTC_DATA 0x71 /* I/O port address for data read/write */
+
+/*
+ * Register A definitions
+ */
+#define RTC_A 0x0a /* register A address */
+#define RTC_UIP 0x80 /* Update in progress bit */
+#define RTC_DIV0 0x00 /* Time base of 4.194304 MHz */
+#define RTC_DIV1 0x10 /* Time base of 1.048576 MHz */
+#define RTC_DIV2 0x20 /* Time base of 32.768 KHz */
+#define RTC_RATE6 0x06 /* interrupt rate of 976.562 */
+
+/*
+ * Register B definitions
+ */
+#define RTC_B 0x0b /* register B address */
+#define RTC_SET 0x80 /* stop updates for time set */
+#define RTC_PIE 0x40 /* Periodic interrupt enable */
+#define RTC_AIE 0x20 /* Alarm interrupt enable */
+#define RTC_UIE 0x10 /* Update ended interrupt enable */
+#define RTC_SQWE 0x08 /* Square wave enable */
+#define RTC_DM 0x04 /* Date mode, 1 = binary, 0 = BCD */
+#define RTC_HM 0x02 /* hour mode, 1 = 24 hour, 0 = 12 hour */
+#define RTC_DSE 0x01 /* Daylight savings enable */
+
+/*
+ * Register C definitions
+ */
+#define RTC_C 0x0c /* register C address */
+#define RTC_IRQF 0x80 /* IRQ flag */
+#define RTC_PF 0x40 /* PF flag bit */
+#define RTC_AF 0x20 /* AF flag bit */
+#define RTC_UF 0x10 /* UF flag bit */
+
+/*
+ * Register D definitions
+ */
+#define RTC_D 0x0d /* register D address */
+#define RTC_VRT 0x80 /* Valid RAM and time bit */
+
+#define RTC_NREG 0x0e /* number of RTC registers */
+#define RTC_NREGP 0x0a /* number of RTC registers to set time */
+
+#define RTCRTIME _IOR('c', 0x01, struct rtc_st) /* Read time from RTC */
+#define RTCSTIME _IOW('c', 0x02, struct rtc_st) /* Set time into RTC */
+
+struct rtc_st {
+ char rtc_sec;
+ char rtc_asec;
+ char rtc_min;
+ char rtc_amin;
+ char rtc_hr;
+ char rtc_ahr;
+ char rtc_dow;
+ char rtc_dom;
+ char rtc_mon;
+ char rtc_yr;
+ char rtc_statusa;
+ char rtc_statusb;
+ char rtc_statusc;
+ char rtc_statusd;
+};
+
+/*
+ * this macro reads contents of real time clock to specified buffer
+ */
+#define load_rtc(regs) \
+{\
+ int i; \
+ \
+ for (i = 0; i < RTC_NREG; i++) { \
+ outb(RTC_ADDR, i); \
+ regs[i] = inb(RTC_DATA); \
+ } \
+}
+
+/*
+ * this macro writes contents of specified buffer to real time clock
+ */
+#define save_rtc(regs) \
+{ \
+ int i; \
+ for (i = 0; i < RTC_NREGP; i++) { \
+ outb(RTC_ADDR, i); \
+ outb(RTC_DATA, regs[i]);\
+ } \
+}
+
+extern int readtodc(uint64_t *tp);
+extern int writetodc(void);
+
+#endif /* _RTC_H_ */