darwin-xnu/osfmk/i386/machine_routines.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22#include <i386/machine_routines.h>
  23#include <i386/io_map_entries.h>
  24#include <i386/cpuid.h>
  25#include <i386/fpu.h>
  26#include <kern/processor.h>
  27#include <kern/machine.h>
  28#include <kern/cpu_data.h>
  29#include <kern/cpu_number.h>
  30#include <kern/thread.h>
  31#include <i386/cpu_data.h>
  32#include <i386/machine_cpu.h>
  33#include <i386/mp.h>
  34#include <i386/mp_events.h>
  35#include <i386/cpu_threads.h>
  36#include <i386/pmap.h>
  37#include <i386/misc_protos.h>
  38#include <mach/vm_param.h>
  39
  40#define MIN(a,b) ((a)<(b)? (a) : (b))
  41
  42extern void     initialize_screen(Boot_Video *, unsigned int);
  43extern void     wakeup(void *);
  44
  45static int max_cpus_initialized = 0;
  46
  47#define MAX_CPUS_SET    0x1
  48#define MAX_CPUS_WAIT   0x2
  49
  50/* IO memory map services */
  51
  52/* Map memory map IO space */
  53vm_offset_t ml_io_map(
  54        vm_offset_t phys_addr, 
  55        vm_size_t size)
  56{
  57        return(io_map(phys_addr,size));
  58}
  59
  60/* boot memory allocation */
  61vm_offset_t ml_static_malloc(
  62                             __unused vm_size_t size)
  63{
  64        return((vm_offset_t)NULL);
  65}
  66
  67vm_offset_t
  68ml_static_ptovirt(
  69        vm_offset_t paddr)
  70{
  71    return (vm_offset_t)((unsigned) paddr | LINEAR_KERNEL_ADDRESS);
  72} 
  73
  74
  75/*
  76 *      Routine:        ml_static_mfree
  77 *      Function:
  78 */
  79void
  80ml_static_mfree(
  81        vm_offset_t vaddr,
  82        vm_size_t size)
  83{
  84        vm_offset_t vaddr_cur;
  85        ppnum_t ppn;
  86
  87        if (vaddr < VM_MIN_KERNEL_ADDRESS) return;
  88
  89        assert((vaddr & (PAGE_SIZE-1)) == 0); /* must be page aligned */
  90
  91        for (vaddr_cur = vaddr;
  92             vaddr_cur < round_page_32(vaddr+size);
  93             vaddr_cur += PAGE_SIZE) {
  94                ppn = pmap_find_phys(kernel_pmap, (addr64_t)vaddr_cur);
  95                if (ppn != (vm_offset_t)NULL) {
  96                        pmap_remove(kernel_pmap, (addr64_t)vaddr_cur, (addr64_t)(vaddr_cur+PAGE_SIZE));
  97                        vm_page_create(ppn,(ppn+1));
  98                        vm_page_wire_count--;
  99                }
 100        }
 101}
 102
 103/* virtual to physical on wired pages */
 104vm_offset_t ml_vtophys(
 105        vm_offset_t vaddr)
 106{
 107        return  kvtophys(vaddr);
 108}
 109
 110/* Interrupt handling */
 111
 112/* Initialize Interrupts */
 113void ml_init_interrupt(void)
 114{
 115        (void) ml_set_interrupts_enabled(TRUE);
 116}
 117
 118/* Get Interrupts Enabled */
 119boolean_t ml_get_interrupts_enabled(void)
 120{
 121  unsigned long flags;
 122
 123  __asm__ volatile("pushf; popl %0" :  "=r" (flags));
 124  return (flags & EFL_IF) != 0;
 125}
 126
 127/* Set Interrupts Enabled */
 128boolean_t ml_set_interrupts_enabled(boolean_t enable)
 129{
 130  unsigned long flags;
 131
 132  __asm__ volatile("pushf; popl %0" :  "=r" (flags));
 133
 134 if (enable)
 135        __asm__ volatile("sti");
 136  else
 137        __asm__ volatile("cli");
 138
 139  return (flags & EFL_IF) != 0;
 140}
 141
 142/* Check if running at interrupt context */
 143boolean_t ml_at_interrupt_context(void)
 144{
 145        return get_interrupt_level() != 0;
 146}
 147
 148/* Generate a fake interrupt */
 149void ml_cause_interrupt(void)
 150{
 151        panic("ml_cause_interrupt not defined yet on Intel");
 152}
 153
 154void ml_thread_policy(
 155        thread_t thread,
 156        unsigned policy_id,
 157        unsigned policy_info)
 158{
 159        if (policy_id == MACHINE_GROUP)
 160                thread_bind(thread, master_processor);
 161
 162        if (policy_info & MACHINE_NETWORK_WORKLOOP) {
 163                spl_t           s = splsched();
 164
 165                thread_lock(thread);
 166
 167                set_priority(thread, thread->priority + 1);
 168
 169                thread_unlock(thread);
 170                splx(s);
 171        }
 172}
 173
 174/* Initialize Interrupts */
 175void ml_install_interrupt_handler(
 176        void *nub,
 177        int source,
 178        void *target,
 179        IOInterruptHandler handler,
 180        void *refCon)  
 181{
 182        boolean_t current_state;
 183
 184        current_state = ml_get_interrupts_enabled();
 185
 186        PE_install_interrupt_handler(nub, source, target,
 187                                     (IOInterruptHandler) handler, refCon);
 188
 189        (void) ml_set_interrupts_enabled(current_state);
 190
 191        initialize_screen(0, kPEAcquireScreen);
 192}
 193
 194static void
 195cpu_idle(void)
 196{
 197        __asm__ volatile("sti; hlt": : :"memory");
 198}
 199void (*cpu_idle_handler)(void) = cpu_idle;
 200
 201void
 202machine_idle(void)
 203{
 204        cpu_core_t      *my_core = cpu_core();
 205        int             others_active;
 206
 207        /*
 208         * We halt this cpu thread
 209         * unless kernel param idlehalt is false and no other thread
 210         * in the same core is active - if so, don't halt so that this
 211         * core doesn't go into a low-power mode.
 212         */
 213        others_active = !atomic_decl_and_test(
 214                                (long *) &my_core->active_threads, 1);
 215        if (idlehalt || others_active) {
 216                DBGLOG(cpu_handle, cpu_number(), MP_IDLE);
 217                cpu_idle_handler();
 218                DBGLOG(cpu_handle, cpu_number(), MP_UNIDLE);
 219        } else {
 220                __asm__ volatile("sti");
 221        }
 222        atomic_incl((long *) &my_core->active_threads, 1);
 223}
 224
 225void
 226machine_signal_idle(
 227        processor_t processor)
 228{
 229        cpu_interrupt(PROCESSOR_DATA(processor, slot_num));
 230}
 231
 232kern_return_t
 233ml_processor_register(
 234        cpu_id_t        cpu_id,
 235        uint32_t        lapic_id,
 236        processor_t     *processor_out,
 237        ipi_handler_t   *ipi_handler,
 238        boolean_t       boot_cpu)
 239{
 240        int             target_cpu;
 241        cpu_data_t      *this_cpu_datap;
 242
 243        this_cpu_datap = cpu_data_alloc(boot_cpu);
 244        if (this_cpu_datap == NULL) {
 245                return KERN_FAILURE;
 246        }
 247        target_cpu = this_cpu_datap->cpu_number;
 248        assert((boot_cpu && (target_cpu == 0)) ||
 249              (!boot_cpu && (target_cpu != 0)));
 250
 251        lapic_cpu_map(lapic_id, target_cpu);
 252
 253        this_cpu_datap->cpu_id = cpu_id;
 254        this_cpu_datap->cpu_phys_number = lapic_id;
 255
 256        this_cpu_datap->cpu_console_buf = console_cpu_alloc(boot_cpu);
 257        if (this_cpu_datap->cpu_console_buf == NULL)
 258                goto failed;
 259
 260        if (!boot_cpu) {
 261                this_cpu_datap->cpu_pmap = pmap_cpu_alloc(boot_cpu);
 262                if (this_cpu_datap->cpu_pmap == NULL)
 263                        goto failed;
 264
 265                this_cpu_datap->cpu_processor = cpu_processor_alloc(boot_cpu);
 266                if (this_cpu_datap->cpu_processor == NULL)
 267                        goto failed;
 268                processor_init(this_cpu_datap->cpu_processor, target_cpu);
 269        }
 270
 271        *processor_out = this_cpu_datap->cpu_processor;
 272        *ipi_handler = NULL;
 273
 274        return KERN_SUCCESS;
 275
 276failed:
 277        cpu_processor_free(this_cpu_datap->cpu_processor);
 278        pmap_cpu_free(this_cpu_datap->cpu_pmap);
 279        console_cpu_free(this_cpu_datap->cpu_console_buf);
 280        return KERN_FAILURE;
 281}
 282
 283void
 284ml_cpu_get_info(ml_cpu_info_t *cpu_infop)
 285{
 286        boolean_t       os_supports_sse;
 287        i386_cpu_info_t *cpuid_infop;
 288
 289        if (cpu_infop == NULL)
 290                return;
 291 
 292        /*
 293         * Are we supporting XMM/SSE/SSE2?
 294         * As distinct from whether the cpu has these capabilities.
 295         */
 296        os_supports_sse = get_cr4() & CR4_XMM;
 297        if ((cpuid_features() & CPUID_FEATURE_SSE2) && os_supports_sse)
 298                cpu_infop->vector_unit = 4;
 299        else if ((cpuid_features() & CPUID_FEATURE_SSE) && os_supports_sse)
 300                cpu_infop->vector_unit = 3;
 301        else if (cpuid_features() & CPUID_FEATURE_MMX)
 302                cpu_infop->vector_unit = 2;
 303        else
 304                cpu_infop->vector_unit = 0;
 305
 306        cpuid_infop  = cpuid_info();
 307
 308        cpu_infop->cache_line_size = cpuid_infop->cache_linesize; 
 309
 310        cpu_infop->l1_icache_size = cpuid_infop->cache_size[L1I];
 311        cpu_infop->l1_dcache_size = cpuid_infop->cache_size[L1D];
 312  
 313        if (cpuid_infop->cache_size[L2U] > 0) {
 314            cpu_infop->l2_settings = 1;
 315            cpu_infop->l2_cache_size = cpuid_infop->cache_size[L2U];
 316        } else {
 317            cpu_infop->l2_settings = 0;
 318            cpu_infop->l2_cache_size = 0xFFFFFFFF;
 319        }
 320
 321        if (cpuid_infop->cache_size[L3U] > 0) {
 322            cpu_infop->l2_settings = 1;
 323            cpu_infop->l2_cache_size = cpuid_infop->cache_size[L3U];
 324        } else {
 325            cpu_infop->l3_settings = 0;
 326            cpu_infop->l3_cache_size = 0xFFFFFFFF;
 327        }
 328}
 329
 330void
 331ml_init_max_cpus(unsigned long max_cpus)
 332{
 333        boolean_t current_state;
 334
 335        current_state = ml_set_interrupts_enabled(FALSE);
 336        if (max_cpus_initialized != MAX_CPUS_SET) {
 337                if (max_cpus > 0 && max_cpus <= MAX_CPUS) {
 338                        /*
 339                         * Note: max_cpus is the number of enable processors
 340                         * that ACPI found; max_ncpus is the maximum number
 341                         * that the kernel supports or that the "cpus="
 342                         * boot-arg has set. Here we take int minimum.
 343                         */
 344                        machine_info.max_cpus = MIN(max_cpus, max_ncpus);
 345                }
 346                if (max_cpus_initialized == MAX_CPUS_WAIT)
 347                        wakeup((event_t)&max_cpus_initialized);
 348                max_cpus_initialized = MAX_CPUS_SET;
 349        }
 350        (void) ml_set_interrupts_enabled(current_state);
 351}
 352
 353int
 354ml_get_max_cpus(void)
 355{
 356        boolean_t current_state;
 357
 358        current_state = ml_set_interrupts_enabled(FALSE);
 359        if (max_cpus_initialized != MAX_CPUS_SET) {
 360                max_cpus_initialized = MAX_CPUS_WAIT;
 361                assert_wait((event_t)&max_cpus_initialized, THREAD_UNINT);
 362                (void)thread_block(THREAD_CONTINUE_NULL);
 363        }
 364        (void) ml_set_interrupts_enabled(current_state);
 365        return(machine_info.max_cpus);
 366}
 367
 368/*
 369 * This is called from the machine-independent routine cpu_up()
 370 * to perform machine-dependent info updates. Defer to cpu_thread_init().
 371 */
 372void
 373ml_cpu_up(void)
 374{
 375        return;
 376}
 377
 378/*
 379 * This is called from the machine-independent routine cpu_down()
 380 * to perform machine-dependent info updates.
 381 */
 382void
 383ml_cpu_down(void)
 384{
 385        return;
 386}
 387
 388/* Stubs for pc tracing mechanism */
 389
 390int *pc_trace_buf;
 391int pc_trace_cnt = 0;
 392
 393int
 394set_be_bit(void)
 395{
 396  return(0);
 397}
 398
 399int
 400clr_be_bit(void)
 401{
 402  return(0);
 403}
 404
 405int
 406be_tracing(void)
 407{
 408  return(0);
 409}
 410
 411/*
 412 * The following are required for parts of the kernel
 413 * that cannot resolve these functions as inlines:
 414 */
 415extern thread_t current_act(void);
 416thread_t
 417current_act(void)
 418{
 419  return(current_thread_fast());
 420}
 421
 422#undef current_thread
 423extern thread_t current_thread(void);
 424thread_t
 425current_thread(void)
 426{
 427  return(current_thread_fast());
 428}
 429
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.