/* * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 2.0 (the "License"). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Mach Operating System * Copyright (c) 1990 Carnegie-Mellon University * Copyright (c) 1989 Carnegie-Mellon University * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ /* * INTEL CORPORATION PROPRIETARY INFORMATION * * This software is supplied under the terms of a license agreement or * nondisclosure agreement with Intel Corporation and may not be copied * nor disclosed except in accordance with the terms of that agreement. * * Copyright 1988, 1989 Intel Corporation */ /* * Copyright 1993 NeXT, Inc. * All rights reserved. */ #include "libsaio.h" /* * keyboard controller (8042) I/O port addresses */ #define PORT_A 0x60 /* port A */ #define PORT_B 0x64 /* port B */ /* * keyboard controller command */ #define CMD_WOUT 0xd1 /* write controller's output port */ /* * keyboard controller status flags */ #define KB_INFULL 0x2 /* input buffer full */ #define KB_OUTFULL 0x1 /* output buffer full */ #define KB_A20 0x9f /* enable A20, enable output buffer full interrupt enable data line disable clock line */ //========================================================================== // Enable A20 gate to be able to access memory above 1MB static inline void flushKeyboardInputBuffer() { unsigned char ret; /* Apparently all flags on means that they're invalid and that the code should stop trying to check them because they'll never change */ do { ret = inb(PORT_B); } while( (ret != 0xff) && (ret & KB_INFULL)); } void enableA20() { /* make sure that the input buffer is empty */ flushKeyboardInputBuffer(); /* make sure that the output buffer is empty */ if (inb(PORT_B) & KB_OUTFULL) (void)inb(PORT_A); /* make sure that the input buffer is empty */ flushKeyboardInputBuffer(); /* write output port */ outb(PORT_B, CMD_WOUT); delay(100); /* wait until command is accepted */ flushKeyboardInputBuffer(); outb(PORT_A, KB_A20); delay(100); /* wait until done */ flushKeyboardInputBuffer(); } // Define the structure of an interrupt descriptor in terms of four 16-bit words. struct int_desc { uint32_t offset_15_0:16; uint32_t segment_selector:16; uint32_t flags:16; uint32_t offset_31_16:16; }; // An x86 table register (e.g. GDTR, LDTR, IDTR) // NOTE: If _operand_ size is 16-bit the base is 24-bit with the top 8-bits zero filled typedef struct { uint16_t limit; uint32_t base; } __attribute__((packed)) x86_table_register; #ifndef BOOT1 // Define zero-filled IDT large enough for all possible exceptions struct int_desc Idt[ 32 ]; // Reference to _Idtr_prot in i386/libsaio/asm.s extern x86_table_register Idtr_prot; // Reference to _gp_fault_handler in i386/libsaio/asm.s extern struct {} gp_fault_handler; void initIdt(void) { // It should be zeroed anyway but just in case. // This ensures that the P flag is 0 on all unused descriptors. bzero(Idt, sizeof(Idt)); // Install the #GP handler Idt[13] = (struct int_desc){ (uintptr_t)&gp_fault_handler & 0xFFFF, 0x08, // CS=08h 0x8E00, // P=1, DPL=0, Interrupt gate (uintptr_t)&gp_fault_handler >> 16 }; // Set up the IDTR to point to the new interrupt table Idtr_prot = (x86_table_register){ sizeof(Idt) - 1, (uintptr_t)Idt }; // Load IDTR asm volatile ("lidtl %0" : : "m"(Idtr_prot) ); } #endif typedef enum { eax, ebx, ecx, edx } cpuid_register_t; static inline void do_cpuid(uint32_t selector, uint32_t *data) { asm volatile ("cpuid" : "=a" (data[0]), "=b" (data[1]), "=c" (data[2]), "=d" (data[3]) : "a"(selector)); } BOOL cpuHasIA32e() { uint32_t cpuid_result[4]; do_cpuid(0x80000001, cpuid_result); return (cpuid_result[3 /*edx*/] & (1<<29)) != 0; } static const uint32_t cpuid_Genu = ('G' << 0) | ('e' << 8) | ('n' << 16) | ('u' << 24); static const uint32_t cpuid_ineI = ('i' << 0) | ('n' << 8) | ('e' << 16) | ('I' << 24); static const uint32_t cpuid_ntel = ('n' << 0) | ('t' << 8) | ('e' << 16) | ('l' << 24); BOOL cpuIsGenuineIntel(uint32_t *pMaxCpuid) { uint32_t cpuid_result[4]; do_cpuid(0, cpuid_result); if(pMaxCpuid != NULL) *pMaxCpuid = cpuid_result[eax]; return (cpuid_result[ebx] == cpuid_Genu) && (cpuid_result[edx] == cpuid_ineI) && (cpuid_result[ecx] == cpuid_ntel); } #define bit(n) (1ULL << (n)) #define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1)) #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l) // Returns the full family ID, taking into account the extended family ID if applicable. uint32_t cpuIntelFamily() { uint32_t cpuid_result[4]; do_cpuid(1, cpuid_result); uint32_t family = bitfield(cpuid_result[eax],11,8); if(family == 0x0f) { family += bitfield(cpuid_result[eax],27,20); } return family; } // Returns the full model ID, taking into account the extended model ID if applicable. uint32_t cpuIntelModel() { uint32_t cpuid_result[4]; do_cpuid(1, cpuid_result); uint32_t family = bitfield(cpuid_result[eax],11,8); uint32_t model = bitfield(cpuid_result[eax],7,4); if( (family == 0x06) || (family == 0x0f) ) { model += bitfield(cpuid_result[eax],19,16) << 4; } return model; } //========================================================================== // Check to see that this is a supported hardware configuration. // If this hardware is supported, return 0. // If this hardware is not supported, return an error code. int checkForSupportedHardware() { uint32_t cpuid_result[4]; do_cpuid(1, cpuid_result); if ((cpuid_result[3] & 0x04000000) == 0) { // Missing SSE2 return 2; } return 0; } #ifndef BOOT1 //========================================================================== // Return the platform name for this hardware. // void getPlatformName(char *nameBuf) { strcpy(nameBuf, "ACPI"); } #endif