Ticket #6310: x86_64_kernel_sources.finished.patch

File x86_64_kernel_sources.finished.patch, 256.0 KB (added by mmlr, 14 years ago)
  • src/system/kernel/arch/x86_64/arch_elf.cpp

     
     1/*
     2 * Copyright 2004-2010, Haiku Inc. All Rights Reserved.
     3 * Distributed under the terms of the MIT license.
     4 *
     5 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
     6 * Distributed under the terms of the NewOS License.
     7 */
     8
     9#include <KernelExport.h>
     10
     11#include <elf_priv.h>
     12#include <arch/elf.h>
     13
     14
     15//#define TRACE_ARCH_ELF
     16#ifdef TRACE_ARCH_ELF
     17#   define TRACE(x) dprintf x
     18#else
     19#   define TRACE(x) ;
     20#endif
     21
     22
     23#ifdef TRACE_ARCH_ELF
     24static const char *kRelocations[] = {
     25    "R_X86_64_NONE",
     26    "R_X86_64_32",          /* add symbol value */
     27    "R_X86_64_PC32",        /* add PC relative symbol value */
     28    "R_X86_64_GOT32",       /* add PC relative GOT offset */
     29    "R_X86_64_PLT32",       /* add PC relative PLT offset */
     30    "R_X86_64_COPY",        /* copy data from shared object */
     31    "R_X86_64_GLOB_DAT",        /* set GOT entry to data address */
     32    "R_X86_64_JMP_SLOT",        /* set GOT entry to code address */
     33    "R_X86_64_RELATIVE",        /* add load address of shared object */
     34    "R_X86_64_GOTOFF",      /* add GOT relative symbol address */
     35};
     36#endif
     37
     38
     39static bool
     40is_in_image(struct elf_image_info *image, addr_t address)
     41{
     42    return (address >= image->text_region.start
     43            && address < image->text_region.start + image->text_region.size)
     44        || (address >= image->data_region.start
     45            && address < image->data_region.start + image->data_region.size);
     46}
     47
     48
     49int arch_elf_relocate_rel(struct elf_image_info *image,
     50    struct elf_image_info *resolveImage, struct Elf64_Rel *rel, int relLength)
     51{
     52    addr_t S;
     53    addr_t A;
     54    addr_t P;
     55    addr_t finalAddress;
     56    addr_t *resolveAddress;
     57    int i;
     58
     59    S = A = P = 0;
     60
     61    for (i = 0; i * (int)sizeof(struct Elf64_Rel) < relLength; i++) {
     62        TRACE(("looking at rel type %s, offset 0x%lx\n",
     63            kRelocations[ELF64_R_TYPE(rel[i].r_info)], rel[i].r_offset));
     64
     65        // calc S
     66        switch (ELF64_R_TYPE(rel[i].r_info)) {
     67            case R_X86_64_64:
     68            case R_X86_64_PC32:
     69            case R_X86_64_GLOB_DAT:
     70            case R_X86_64_JMP_SLOT:
     71            case R_X86_64_GOTOFF:
     72            {
     73                struct Elf64_Sym *symbol;
     74                status_t status;
     75
     76                symbol = SYMBOL64(image, ELF64_R_SYM(rel[i].r_info));
     77/* TODO: Add resolove symbol for 64bit elf */
     78//              status = elf_resolve_symbol(image, symbol, resolveImage, &S);
     79
     80                if (status < B_OK)
     81                    return status;
     82                TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
     83            }
     84        }
     85        // calc A
     86        switch (ELF64_R_TYPE(rel[i].r_info)) {
     87            case R_X86_64_64:
     88            case R_X86_64_PC32:
     89            case R_X86_64_GOT32:
     90            case R_X86_64_PLT32:
     91            case R_X86_64_RELATIVE:
     92            case R_X86_64_GOTOFF:
     93                A = *(addr_t *)(image->text_region.delta + rel[i].r_offset);
     94                TRACE(("A %p\n", (void *)A));
     95                break;
     96        }
     97        // calc P
     98        switch (ELF64_R_TYPE(rel[i].r_info)) {
     99            case R_X86_64_PC32:
     100            case R_X86_64_GOT32:
     101            case R_X86_64_PLT32:
     102                P = image->text_region.delta + rel[i].r_offset;
     103                TRACE(("P %p\n", (void *)P));
     104                break;
     105        }
     106
     107        switch (ELF64_R_TYPE(rel[i].r_info)) {
     108            case R_X86_64_NONE:
     109                continue;
     110            case R_X86_64_64:
     111                finalAddress = S + A;
     112                break;
     113            case R_X86_64_PC32:
     114                finalAddress = S + A - P;
     115                break;
     116            case R_X86_64_RELATIVE:
     117                // B + A;
     118                finalAddress = image->text_region.delta + A;
     119                break;
     120            case R_X86_64_JMP_SLOT:
     121            case R_X86_64_GLOB_DAT:
     122                finalAddress = S;
     123                break;
     124
     125            default:
     126                dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
     127                    ELF64_R_TYPE(rel[i].r_info));
     128                return B_BAD_DATA;
     129        }
     130
     131        resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset);
     132
     133        if (!is_in_image(image, (addr_t)resolveAddress)) {
     134            dprintf("arch_elf_relocate_rel: invalid offset %#lx\n",
     135                rel[i].r_offset);
     136            return B_BAD_ADDRESS;
     137        }
     138
     139        *resolveAddress = finalAddress;
     140        TRACE(("-> offset %#lx = %#lx\n",
     141            (image->text_region.delta + rel[i].r_offset), finalAddress));
     142    }
     143
     144    return B_NO_ERROR;
     145}
     146
     147
     148int
     149arch_elf_relocate_rela(struct elf_image_info *image,
     150    struct elf_image_info *resolveImage, struct Elf64_Rela *rela, int relLength)
     151{
     152    addr_t S;
     153    addr_t A;
     154    addr_t P;
     155    addr_t finalAddress;
     156    addr_t *resolveAddress;
     157    int i;
     158
     159    S = A = P = 0;
     160
     161    for (i = 0; i * (int)sizeof(struct Elf64_Rela) < relLength; i++) {
     162        TRACE(("looking at rel type %s, offset 0x%lx\n",
     163            kRelocations[ELF64_R_TYPE(rela[i].r_info)], rela[i].r_offset));
     164
     165        // calc S
     166        switch (ELF64_R_TYPE(rela[i].r_info)) {
     167            case R_X86_64_32:
     168            case R_X86_64_PC32:
     169            case R_X86_64_GLOB_DAT:
     170            case R_X86_64_JMP_SLOT:
     171            {
     172                struct Elf64_Sym *symbol;
     173                status_t status;
     174
     175                symbol = SYMBOL64(image, ELF64_R_SYM(rela[i].r_info));
     176/* TODO: ADD RESOLVE SYMBOL FOR ELF64 */
     177//              status = boot_elf64_resolve_symbol(image, symbol, &S);
     178
     179                if (status < B_OK)
     180                    return status;
     181                TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
     182            }
     183        }
     184        // calc A
     185        switch (ELF64_R_TYPE(rela[i].r_info)) {
     186            case R_X86_64_32:
     187            case R_X86_64_PC32:
     188            case R_X86_64_GOT32:
     189            case R_X86_64_PLT32:
     190            case R_X86_64_RELATIVE:
     191            case R_X86_64_GOTOFF:
     192                A = *(addr_t *)(image->text_region.delta + rela[i].r_offset);
     193                TRACE(("A %p\n", (void *)A));
     194                break;
     195        }
     196        // calc P
     197        switch (ELF64_R_TYPE(rela[i].r_info)) {
     198            case R_X86_64_PC32:
     199            case R_X86_64_GOT32:
     200            case R_X86_64_PLT32:
     201                P = image->text_region.delta + rela[i].r_offset;
     202                TRACE(("P %p\n", (void *)P));
     203                break;
     204        }
     205
     206        switch (ELF64_R_TYPE(rela[i].r_info)) {
     207            case R_X86_64_NONE:
     208                continue;
     209            case R_X86_64_32:
     210                finalAddress = S + A;
     211                break;
     212            case R_X86_64_PC32:
     213                finalAddress = S + A - P;
     214                break;
     215            case R_X86_64_RELATIVE:
     216                // B + A;
     217                finalAddress = image->text_region.delta + A;
     218                break;
     219            case R_X86_64_JMP_SLOT:
     220            case R_X86_64_GLOB_DAT:
     221                finalAddress = S;
     222                break;
     223
     224            default:
     225                dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
     226                    ELF64_R_TYPE(rela[i].r_info));
     227                return B_BAD_DATA;
     228        }
     229
     230        resolveAddress = (addr_t *)(image->text_region.delta + rela[i].r_offset);
     231
     232        *resolveAddress = finalAddress;
     233        TRACE(("-> offset %#lx = %#lx\n",
     234            (image->text_region.delta + rela[i].r_offset), finalAddress));
     235    }
     236
     237    return B_NO_ERROR;
     238}
     239
     240
     241int
     242arch_elf_relocate_rel(struct elf_image_info *image,
     243    struct elf_image_info *resolveImage, struct Elf32_Rel *rel, int relLength)
     244{
     245    addr_t S;
     246    addr_t A;
     247    addr_t P;
     248    addr_t finalAddress;
     249    addr_t *resolveAddress;
     250    int i;
     251
     252    S = A = P = 0;
     253
     254    for (i = 0; i * (int)sizeof(struct Elf32_Rel) < relLength; i++) {
     255        TRACE(("looking at rel type %s, offset 0x%lx\n",
     256            kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset));
     257
     258        // calc S
     259        switch (ELF32_R_TYPE(rel[i].r_info)) {
     260            case R_386_32:
     261            case R_386_PC32:
     262            case R_386_GLOB_DAT:
     263            case R_386_JMP_SLOT:
     264            case R_386_GOTOFF:
     265            {
     266                struct Elf32_Sym *symbol;
     267                status_t status;
     268
     269                symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
     270
     271                status = elf_resolve_symbol(image, symbol, resolveImage, &S);
     272
     273                if (status < B_OK)
     274                    return status;
     275                TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
     276            }
     277        }
     278        // calc A
     279        switch (ELF32_R_TYPE(rel[i].r_info)) {
     280            case R_386_32:
     281            case R_386_PC32:
     282            case R_386_GOT32:
     283            case R_386_PLT32:
     284            case R_386_RELATIVE:
     285            case R_386_GOTOFF:
     286            case R_386_GOTPC:
     287                A = *(addr_t *)(image->text_region.delta + rel[i].r_offset);
     288                TRACE(("A %p\n", (void *)A));
     289                break;
     290        }
     291        // calc P
     292        switch (ELF32_R_TYPE(rel[i].r_info)) {
     293            case R_386_PC32:
     294            case R_386_GOT32:
     295            case R_386_PLT32:
     296            case R_386_GOTPC:
     297                P = image->text_region.delta + rel[i].r_offset;
     298                TRACE(("P %p\n", (void *)P));
     299                break;
     300        }
     301
     302        switch (ELF32_R_TYPE(rel[i].r_info)) {
     303            case R_386_NONE:
     304                continue;
     305            case R_386_32:
     306                finalAddress = S + A;
     307                break;
     308            case R_386_PC32:
     309                finalAddress = S + A - P;
     310                break;
     311            case R_386_RELATIVE:
     312                // B + A;
     313                finalAddress = image->text_region.delta + A;
     314                break;
     315            case R_386_JMP_SLOT:
     316            case R_386_GLOB_DAT:
     317                finalAddress = S;
     318                break;
     319
     320            default:
     321                dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
     322                    ELF32_R_TYPE(rel[i].r_info));
     323                return B_BAD_DATA;
     324        }
     325
     326        resolveAddress = (addr_t *)(image->text_region.delta + rel[i].r_offset);
     327
     328        if (!is_in_image(image, (addr_t)resolveAddress)) {
     329            dprintf("arch_elf_relocate_rel: invalid offset %#lx\n",
     330                rel[i].r_offset);
     331            return B_BAD_ADDRESS;
     332        }
     333
     334        *resolveAddress = finalAddress;
     335        TRACE(("-> offset %#lx = %#lx\n",
     336            (image->text_region.delta + rel[i].r_offset), finalAddress));
     337    }
     338
     339    return B_NO_ERROR;
     340}
     341
     342
     343
     344
     345int
     346arch_elf_relocate_rela(struct elf_image_info *image,
     347    struct elf_image_info *resolveImage, struct Elf32_Rela *rel, int relLength)
     348{
     349    dprintf("arch_elf_relocate_rela: not supported on x86\n");
     350    return B_ERROR;
     351}
  • src/system/kernel/arch/x86_64/arch_thread.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     9 * Distributed under the terms of the NewOS License.
     10 */
     11
     12
     13#include <arch/thread.h>
     14
     15#include <string.h>
     16
     17#include <arch/user_debugger.h>
     18#include <arch_cpu.h>
     19#include <cpu.h>
     20#include <debug.h>
     21#include <kernel.h>
     22#include <ksignal.h>
     23#include <int.h>
     24#include <team.h>
     25#include <thread.h>
     26#include <tls.h>
     27#include <tracing.h>
     28#include <vm/vm_types.h>
     29#include <vm/VMAddressSpace.h>
     30
     31#include "paging/X86_64PagingStructures.h"
     32#include "paging/X86_64VMTranslationMap.h"
     33
     34
     35//#define TRACE_ARCH_THREAD
     36#ifdef TRACE_ARCH_THREAD
     37#   define TRACE(x) dprintf x
     38#else
     39#   define TRACE(x) ;
     40#endif
     41
     42
     43// from arch_interrupts.S
     44extern "C" void x86_64_stack_init(struct farcall *interrupt_stack_offset);
     45extern "C" void x86_64_restore_frame_from_syscall(struct iframe frame);
     46
     47// from arch_cpu.cpp
     48extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState);
     49
     50//from arch_commpage.cpp
     51extern void x86_64_set_syscall_stack(addr_t stackTop);
     52
     53static struct arch_thread sInitialState _ALIGNED(16);
     54    // the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it
     55
     56
     57static inline void
     58set_fs_register(uint32 segment)
     59{
     60    asm("mov %0,%%fs" :: "r" (segment));
     61}
     62
     63
     64static void
     65set_tls_context(struct thread *thread)
     66{
     67    int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
     68
     69    set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage);
     70    set_fs_register((entry << 3) | DPL_USER);
     71}
     72
     73
     74static struct iframe *
     75find_previous_iframe(struct thread *thread, addr_t frame)
     76{
     77    // iterate backwards through the stack frames, until we hit an iframe
     78    while (frame >= thread->kernel_stack_base
     79        && frame < thread->kernel_stack_top) {
     80        addr_t previousFrame = *(addr_t*)frame;
     81        if ((previousFrame & ~IFRAME_TYPE_MASK) == 0) {
     82            if (previousFrame == 0)
     83                return NULL;
     84            return (struct iframe*)frame;
     85        }
     86
     87        frame = previousFrame;
     88    }
     89
     90    return NULL;
     91}
     92
     93static struct iframe*
     94get_previous_iframe(struct iframe* frame)
     95{
     96    if (frame == NULL)
     97        return NULL;
     98
     99    return find_previous_iframe(thread_get_current_thread(), frame->rbp);
     100}
     101
     102static struct iframe*
     103get_current_iframe(void)
     104{
     105    return find_previous_iframe(thread_get_current_thread(), x86_64_read_rbp());
     106}
     107
     108struct iframe *
     109x86_64_get_current_iframe(void)
     110{
     111    return get_current_iframe();
     112}
     113
     114
     115/*!
     116    \brief Returns the current thread's topmost (i.e. most recent)
     117    userland->kernel transition iframe (usually the first one, save for
     118    interrupts in signal handlers).
     119    \return The iframe, or \c NULL, if there is no such iframe (e.g. when
     120            the thread is a kernel thread).
     121*/
     122struct iframe *
     123x86_64_get_user_iframe(void)
     124{
     125    struct iframe* frame = get_current_iframe();
     126
     127    while (frame != NULL) {
     128        if (IFRAME_IS_USER(frame))
     129            return frame;
     130        frame = get_previous_iframe(frame);
     131    }
     132
     133    return NULL;
     134}
     135
     136
     137uint64
     138x86_64_next_page_directory(struct thread *from, struct thread *to)
     139{
     140    VMAddressSpace* toAddressSpace = to->team->address_space;
     141    if (from->team->address_space == toAddressSpace) {
     142        // don't change the pgdir, same address space
     143        return 0;
     144    }
     145
     146    if (toAddressSpace == NULL)
     147        toAddressSpace = VMAddressSpace::Kernel();
     148
     149    return static_cast<X86_64VMTranslationMap*>(toAddressSpace->TranslationMap())
     150        ->PagingStructures()->pgdir_phys;
     151}
     152
     153static uint64 *
     154get_signal_stack(struct thread *thread, struct iframe *frame, int signal)
     155{
     156    // use the alternate signal stack if we should and can
     157    if (thread->signal_stack_enabled
     158        && (thread->sig_action[signal - 1].sa_flags & SA_ONSTACK) != 0
     159        && (frame->user_rsp < thread->signal_stack_base
     160            || frame->user_rsp >= thread->signal_stack_base
     161                + thread->signal_stack_size)) {
     162        return (uint64 *)(thread->signal_stack_base
     163            + thread->signal_stack_size);
     164    }
     165
     166    return (uint64 *)frame->user_rsp;
     167}
     168
     169status_t
     170arch_thread_init(struct kernel_args *args)
     171{
     172    // save one global valid FPU state; it will be copied in the arch dependent
     173    // part of each new thread
     174
     175    asm volatile ("clts; fninit; fnclex;");
     176
     177    x86_64_fxsave(sInitialState.fpu_state);
     178
     179    return B_OK;
     180}
     181
     182
     183status_t
     184arch_team_init_team_struct(struct team *team, bool kernel)
     185{
     186    return B_OK;
     187}
     188
     189
     190status_t
     191arch_thread_init_thread_struct(struct thread *thread)
     192{
     193    // set up an initial state (stack & fpu)
     194    memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread));
     195    return B_OK;
     196}
     197
     198
     199status_t
     200arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void),
     201    void (*entry_func)(void), void (*exit_func)(void))
     202{
     203    addr_t *kstack = (addr_t *)t->kernel_stack_base;
     204    addr_t *kstack_top = (addr_t *)t->kernel_stack_top;
     205    int i;
     206
     207    TRACE(("arch_thread_initialize_kthread_stack: kstack 0x%p, start_func 0x%p, entry_func 0x%p\n",
     208        kstack, start_func, entry_func));
     209
     210    // clear the kernel stack
     211#ifdef DEBUG_KERNEL_STACKS
     212#   ifdef STACK_GROWS_DOWNWARDS
     213    memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0,
     214        KERNEL_STACK_SIZE);
     215#   else
     216    memset(kstack, 0, KERNEL_STACK_SIZE);
     217#   endif
     218#else
     219    memset(kstack, 0, KERNEL_STACK_SIZE);
     220#endif
     221
     222    // set the final return address to be thread_kthread_exit
     223    kstack_top--;
     224    *kstack_top = (addr_t)exit_func;
     225
     226    // set the return address to be the start of the first function
     227    kstack_top--;
     228    *kstack_top = (addr_t)start_func;
     229
     230    // set the return address to be the start of the entry (thread setup)
     231    // function
     232    kstack_top--;
     233    *kstack_top = (addr_t)entry_func;
     234
     235    // simulate pushfl
     236//  kstack_top--;
     237//  *kstack_top = 0x00; // interrupts still disabled after the switch
     238
     239    // simulate initial popad
     240    for (i = 0; i < 8; i++) {
     241        kstack_top--;
     242        *kstack_top = 0;
     243    }
     244
     245    // save the stack position
     246    t->arch_info.current_stack.rsp = kstack_top;
     247    t->arch_info.current_stack.ss = (addr_t *)KERNEL_DATA_SEG;
     248
     249    return B_OK;
     250}
     251
     252
     253status_t
     254arch_thread_init_tls(struct thread *thread)
     255{
     256    uint32 tls[TLS_USER_THREAD_SLOT + 1];
     257
     258    thread->user_local_storage = thread->user_stack_base
     259        + thread->user_stack_size;
     260
     261    // initialize default TLS fields
     262    memset(tls, 0, sizeof(tls));
     263    tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
     264    tls[TLS_THREAD_ID_SLOT] = thread->id;
     265    tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread;
     266
     267    return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls));
     268}
     269
     270
     271void
     272arch_thread_context_switch(struct thread *from, struct thread *to)
     273{
     274    x86_64_set_tss_and_kstack(to->kernel_stack_top);
     275    x86_64_set_syscall_stack(to->kernel_stack_top);
     276
     277    // set TLS GDT entry to the current thread - since this action is
     278    // dependent on the current CPU, we have to do it here
     279    if (to->user_local_storage != 0)
     280        set_tls_context(to);
     281
     282    struct cpu_ent* cpuData = to->cpu;
     283    X86_64PagingStructures* activePagingStructures
     284        = cpuData->arch.active_paging_structures;
     285    VMAddressSpace* toAddressSpace = to->team->address_space;
     286
     287    X86_64PagingStructures* toPagingStructures;
     288    if (toAddressSpace != NULL
     289        && (toPagingStructures = static_cast<X86_64VMTranslationMap*>(
     290                toAddressSpace->TranslationMap())->PagingStructures())
     291                    != activePagingStructures) {
     292        // update on which CPUs the address space is used
     293        int cpu = cpuData->cpu_num;
     294        atomic_and(&activePagingStructures->active_on_cpus,
     295            ~((uint32)1 << cpu));
     296        atomic_or(&toPagingStructures->active_on_cpus, (uint32)1 << cpu);
     297
     298        // assign the new paging structures to the CPU
     299        toPagingStructures->AddReference();
     300        cpuData->arch.active_paging_structures = toPagingStructures;
     301
     302        // set the page directory, if it changes
     303        uint32 newPageDirectory = toPagingStructures->pgdir_phys;
     304        if (newPageDirectory != activePagingStructures->pgdir_phys)
     305            x86_64_swap_pgdir(newPageDirectory);
     306
     307        // This CPU no longer uses the previous paging structures.
     308        activePagingStructures->RemoveReference();
     309    }
     310
     311    gX86SwapFPUFunc(from->arch_info.fpu_state, to->arch_info.fpu_state);
     312    x86_64_context_switch(&from->arch_info, &to->arch_info);
     313}
     314
     315
     316void
     317arch_thread_dump_info(void *info)
     318{
     319    struct arch_thread *at = (struct arch_thread *)info;
     320
     321    kprintf("\trsp: %p\n", at->current_stack.rsp);
     322    kprintf("\tss: %p\n", at->current_stack.ss);
     323    kprintf("\tfpu_state at %p\n", at->fpu_state);
     324}
     325
     326
     327status_t
     328arch_thread_enter_userspace(struct thread *thread, addr_t entry, void *arg1, void *arg2)
     329{
     330    addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
     331    uint64 codeSize = (addr_t)x86_64_end_userspace_thread_exit
     332        - (addr_t)x86_64_userspace_thread_exit;
     333    uint64 args[3];
     334
     335    TRACE(("arch_thread_enter_uspace: entry 0x%lx, args %p %p, ustack_top 0x%lx\n",
     336        entry, args1, args2, stackTop));
     337
     338    // copy the little stub that calls exit_thread() when the thread entry
     339    // function returns, as well as the arguments of the entry function
     340    stackTop -= codeSize;
     341
     342    if (user_memcpy((void *)stackTop, (const void *)&x86_64_userspace_thread_exit, codeSize) < B_OK)
     343        return B_BAD_ADDRESS;
     344
     345    args[0] = stackTop;
     346    args[1] = (uint64)arg1;
     347    args[2] = (uint64)arg2;
     348    stackTop -= sizeof(args);
     349
     350    if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
     351        return B_BAD_ADDRESS;
     352
     353    thread_at_kernel_exit();
     354        // also disables interrupts
     355
     356    // install user breakpoints, if any
     357    if ((thread->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED) != 0)
     358        x86_64_init_user_debug_at_kernel_exit(NULL);
     359
     360    x86_64_set_tss_and_kstack(thread->kernel_stack_top);
     361
     362    // set the CPU dependent GDT entry for TLS
     363    set_tls_context(thread);
     364
     365    x86_64_set_syscall_stack(thread->kernel_stack_top);
     366    x86_64_enter_userspace(entry, stackTop);
     367
     368    return B_OK;
     369}
     370
     371
     372bool
     373arch_on_signal_stack(struct thread *thread)
     374{
     375    struct iframe *frame = get_current_iframe();
     376
     377    return frame->user_rsp >= thread->signal_stack_base
     378        && frame->user_rsp < thread->signal_stack_base
     379            + thread->signal_stack_size;
     380}
     381
     382
     383status_t
     384arch_setup_signal_frame(struct thread *thread, struct sigaction *action, int sig, int sigMask)
     385{
     386    struct iframe *frame = get_current_iframe();
     387    if (!IFRAME_IS_USER(frame)) {
     388        panic("arch_setup_signal_frame(): No user iframe!");
     389        return B_BAD_VALUE;
     390    }
     391
     392    uint64 *signalCode;
     393    addr_t *userRegs;
     394    struct vregs regs;
     395    uint64 buffer[6];
     396    status_t status;
     397
     398    // start stuffing stuff on the user stack
     399    addr_t* userStack = get_signal_stack(thread, frame, sig);
     400
     401    // copy syscall restart info onto the user stack
     402    userStack -= (sizeof(thread->syscall_restart.parameters) + 12 + 3) / 4;
     403    uint32 threadFlags = atomic_and(&thread->flags,
     404        ~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
     405    if (user_memcpy(userStack, &threadFlags, 4) < B_OK
     406        || user_memcpy(userStack + 1, &frame->orig_rax, 4) < B_OK
     407        || user_memcpy(userStack + 2, &frame->orig_rdx, 4) < B_OK)
     408        return B_BAD_ADDRESS;
     409    status = user_memcpy(userStack + 3, thread->syscall_restart.parameters,
     410        sizeof(thread->syscall_restart.parameters));
     411    if (status < B_OK)
     412        return status;
     413
     414    // store the saved regs onto the user stack
     415    regs.rip = frame->rip;
     416    regs.eflags = frame->flags;
     417    regs.rax = frame->rax;
     418    regs.rcx = frame->rcx;
     419    regs.rdx = frame->rdx;
     420    regs.rbp = frame->rbp;
     421    regs.rsp = frame->rsp;
     422    regs.r8 = frame->r8;
     423    regs.r9 = frame->r9;
     424    regs.r10 = frame->r10;
     425    regs.r11 = frame->r11;
     426    regs.r12 = frame->r12;
     427    regs.r13 = frame->r13;
     428    regs.r14 = frame->r14;
     429    regs.r15 = frame->r15;
     430    regs._reserved_1 = frame->user_rsp;
     431    regs._reserved_2[0] = frame->rdi;
     432    regs._reserved_2[1] = frame->rsi;
     433    regs._reserved_2[2] = frame->rbx;
     434    x86_64_fnsave((void *)(&regs.xregs));
     435
     436    userStack -= (sizeof(struct vregs) + 3) / 4;
     437    userRegs = userStack;
     438    status = user_memcpy(userRegs, &regs, sizeof(regs));
     439    if (status < B_OK)
     440        return status;
     441
     442    // now store a code snippet on the stack
     443    userStack -= ((uint64)x86_64_end_return_from_signal + 3
     444        - (uint64)x86_64_return_from_signal) / 4;
     445    signalCode = userStack;
     446    status = user_memcpy(signalCode, (const void *)&x86_64_return_from_signal,
     447        ((uint64)x86_64_end_return_from_signal
     448            - (uint64)x86_64_return_from_signal));
     449    if (status < B_OK)
     450        return status;
     451
     452    // now set up the final part
     453    buffer[0] = (uint64)signalCode; // return address when sa_handler done
     454    buffer[1] = (uint64)sig;                // arguments to sa_handler
     455    buffer[2] = (uint64)action->sa_userdata;
     456    buffer[3] = (uint64)userRegs;
     457
     458    buffer[4] = sigMask;            // Old signal mask to restore
     459    buffer[5] = (uint64)userRegs;   // Int frame + extra regs to restore
     460
     461    userStack -= sizeof(buffer) / 4;
     462
     463    status = user_memcpy(userStack, buffer, sizeof(buffer));
     464    if (status < B_OK)
     465        return status;
     466
     467    frame->user_rsp = (uint64)userStack;
     468    frame->rip = (uint64)action->sa_handler;
     469
     470    return B_OK;
     471}
     472
     473
     474int64
     475arch_restore_signal_frame(void)
     476{
     477    struct thread *thread = thread_get_current_thread();
     478    struct iframe *frame = get_current_iframe();
     479    int32 signalMask;
     480    uint64 *userStack;
     481    struct vregs* regsPointer;
     482    struct vregs regs;
     483
     484    TRACE(("### arch_restore_signal_frame: entry\n"));
     485
     486    userStack = (uint64 *)frame->user_rsp;
     487    if (user_memcpy(&signalMask, &userStack[0], 4) < B_OK
     488        || user_memcpy(&regsPointer, &userStack[1], 4) < B_OK
     489        || user_memcpy(&regs, regsPointer, sizeof(vregs)) < B_OK) {
     490        return B_BAD_ADDRESS;
     491    }
     492
     493    uint64* syscallRestartInfo
     494        = (uint64*)regsPointer + (sizeof(struct vregs) + 3) / 4;
     495    uint32 threadFlags;
     496    if (user_memcpy(&threadFlags, syscallRestartInfo, 4) < B_OK
     497        || user_memcpy(&frame->orig_rax, syscallRestartInfo + 1, 4) < B_OK
     498        || user_memcpy(&frame->orig_rdx, syscallRestartInfo + 2, 4) < B_OK
     499        || user_memcpy(thread->syscall_restart.parameters,
     500            syscallRestartInfo + 3,
     501            sizeof(thread->syscall_restart.parameters)) < B_OK) {
     502        return B_BAD_ADDRESS;
     503    }
     504
     505    // set restart/64bit return value flags from previous syscall
     506    atomic_and(&thread->flags,
     507        ~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
     508    atomic_or(&thread->flags, threadFlags
     509        & (THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
     510
     511    // TODO: Verify that just restoring the old signal mask is right! Bash for
     512    // instance changes the procmask in a signal handler. Those changes are
     513    // lost the way we do it.
     514    atomic_set(&thread->sig_block_mask, signalMask);
     515    update_current_thread_signals_flag();
     516
     517    frame->rip = regs.rip;
     518    frame->flags = regs.eflags;
     519    frame->rax = regs.rax;
     520    frame->rcx = regs.rcx;
     521    frame->rdx = regs.rdx;
     522    frame->rbp = regs.rbp;
     523    frame->rsp = regs.rsp;
     524    frame->r8  = regs.r8;
     525    frame->r9  = regs.r9;
     526    frame->r10 = regs.r10;
     527    frame->r11 = regs.r11;
     528    frame->r12 = regs.r12;
     529    frame->r13 = regs.r13;
     530    frame->r14 = regs.r14;
     531    frame->r15 = regs.r15;
     532    frame->user_rsp = regs._reserved_1;
     533    frame->rdi = regs._reserved_2[0];
     534    frame->rsi = regs._reserved_2[1];
     535    frame->rbx = regs._reserved_2[2];
     536
     537    x86_64_frstor((void *)(&regs.xregs));
     538
     539    TRACE(("### arch_restore_signal_frame: exit\n"));
     540
     541    return (int64)frame->rax | ((int64)frame->rdx << 32);
     542}
     543
     544
     545void
     546arch_store_fork_frame(struct arch_fork_arg *arg)
     547{
     548    struct iframe *frame = get_current_iframe();
     549
     550    // we need to copy the threads current iframe
     551    arg->iframe = *frame;
     552
     553    // we also want fork() to return 0 for the child
     554    arg->iframe.rax = 0;
     555}
     556
     557void
     558arch_restore_fork_frame(struct arch_fork_arg *arg)
     559{
     560    struct thread *thread = thread_get_current_thread();
     561
     562    disable_interrupts();
     563
     564    x86_64_set_tss_and_kstack(thread->kernel_stack_top);
     565
     566    // set the CPU dependent GDT entry for TLS (set the current %fs register)
     567    set_tls_context(thread);
     568
     569    x86_64_restore_frame_from_syscall(arg->iframe);
     570}
     571
     572void
     573arch_syscall_64_bit_return_value(void)
     574{
     575    struct thread* thread = thread_get_current_thread();
     576    atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
     577}
  • src/system/kernel/arch/x86_64/arch_debug_console.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com
     3 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de
     4 * Copyright 2001, Rob Judd <judd@ob-wan.com>
     5 * Copyright 2002, Marcus Overhagen <marcus@overhagen.de>
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     9 * Distributed under the terms of the NewOS License.
     10 */
     11
     12#include "debugger_keymaps.h"
     13
     14#include <KernelExport.h>
     15#include <driver_settings.h>
     16#include <int.h>
     17
     18#include <arch/cpu.h>
     19#include <arch/debug_console.h>
     20#include <boot/stage2.h>
     21#include <debug.h>
     22
     23#include <string.h>
     24#include <stdlib.h>
     25
     26
     27#define INT_PS2_KEYBOARD                0x01
     28
     29#define PS2_PORT_DATA                   0x60
     30#define PS2_PORT_CTRL                   0x64
     31
     32#define PS2_STATUS_OUTPUT_BUFFER_FULL           0x01
     33#define PS2_STATUS_AUX_DATA             0x20
     34
     35
     36enum serial_register_offsets {
     37    SERIAL_TRANSMIT_BUFFER          = 0,
     38    SERIAL_RECEIVE_BUFFER           = 0,
     39    SERIAL_DIVISOR_LATCH_LOW        = 0,
     40    SERIAL_DIVISOR_LATCH_HIGH       = 1,
     41    SERIAL_FIFO_CONTROL         = 2,
     42    SERIAL_LINE_CONTROL         = 3,
     43    SERIAL_MODEM_CONTROL            = 4,
     44    SERIAL_LINE_STATUS          = 5,
     45    SERIAL_MODEM_STATUS         = 6,
     46};
     47
     48enum keycodes {
     49    LEFT_SHIFT      = 42,
     50    RIGHT_SHIFT     = 54,
     51
     52    LEFT_CONTROL        = 29,
     53
     54    LEFT_ALT        = 56,
     55    RIGHT_ALT       = 58,
     56
     57    CURSOR_LEFT     = 75,
     58    CURSOR_RIGHT        = 77,
     59    CURSOR_UP       = 72,
     60    CURSOR_DOWN     = 80,
     61    CURSOR_HOME     = 71,
     62    CURSOR_END      = 79,
     63    PAGE_UP         = 73,
     64    PAGE_DOWN       = 81,
     65
     66    DELETE          = 83,
     67    SYS_REQ         = 84,
     68    F12         = 88,
     69};
     70
     71
     72static const uint32 kSerialBaudRate = 115200;
     73static uint16 sSerialBasePort = 0x3f8;
     74    // COM1 is the default debug output port
     75
     76static bool sKeyboardHandlerInstalled = false;
     77
     78static spinlock sSerialOutputSpinlock = B_SPINLOCK_INITIALIZER;
     79
     80
     81static void
     82put_char(const char c)
     83{
     84    // wait until the transmitter empty bit is set
     85    while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0)
     86        asm volatile ("pause;");
     87
     88    out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER);
     89}
     90
     91
     92static void
     93_arch_debug_serial_putchar(const char c)
     94{
     95    if (c == '\n') {
     96        put_char('\r');
     97        put_char('\n');
     98    } else if (c != '\r')
     99        put_char(c);
     100}
     101
     102
     103/** Minimal keyboard handler to be able to get into the debugger and
     104 *  reboot the machine before the input_server is up and running.
     105 *  It is added as soon as interrupts become available, and removed
     106 *  again if anything else requests the interrupt 1.
     107 */
     108
     109static int32
     110debug_keyboard_interrupt(void *data)
     111{
     112    static bool controlPressed = false;
     113    static bool altPressed = false;
     114    static bool sysReqPressed = false;
     115    uint8 key;
     116
     117    key = in8(PS2_PORT_DATA);
     118    //dprintf("debug_keyboard_interrupt: key = 0x%x\n", key);
     119
     120    if (key & 0x80) {
     121        if (key == LEFT_CONTROL)
     122            controlPressed = false;
     123        else if (key == LEFT_ALT)
     124            altPressed = false;
     125        else if (key == SYS_REQ)
     126            sysReqPressed = false;
     127
     128        return B_HANDLED_INTERRUPT;
     129    }
     130
     131    switch (key) {
     132        case LEFT_CONTROL:
     133            controlPressed = true;
     134            break;
     135
     136        case LEFT_ALT:
     137        case RIGHT_ALT:
     138            altPressed = true;
     139            break;
     140
     141        case SYS_REQ:
     142            sysReqPressed = true;
     143            break;
     144
     145        case DELETE:
     146            if (controlPressed && altPressed)
     147                arch_cpu_shutdown(true);
     148            break;
     149
     150        default:
     151            if (altPressed && sysReqPressed) {
     152                if (debug_emergency_key_pressed(kUnshiftedKeymap[key])) {
     153                    // we probably have lost some keys, so reset our key states
     154                    controlPressed = false;
     155                    sysReqPressed = false;
     156                    altPressed = false;
     157                }
     158            }
     159            break;
     160    }
     161
     162    return B_HANDLED_INTERRUPT;
     163}
     164
     165
     166void
     167arch_debug_remove_interrupt_handler(uint32 line)
     168{
     169    if (line != INT_PS2_KEYBOARD || !sKeyboardHandlerInstalled)
     170        return;
     171
     172    remove_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt,
     173        NULL);
     174    sKeyboardHandlerInstalled = false;
     175}
     176
     177
     178void
     179arch_debug_install_interrupt_handlers(void)
     180{
     181    install_io_interrupt_handler(INT_PS2_KEYBOARD, &debug_keyboard_interrupt,
     182        NULL, 0);
     183    sKeyboardHandlerInstalled = true;
     184}
     185
     186
     187char
     188arch_debug_blue_screen_getchar(void)
     189{
     190
     191    /* polling the keyboard, similar to code in keyboard
     192     * driver, but without using an interrupt
     193     */
     194    static bool shiftPressed = false;
     195    static bool controlPressed = false;
     196    static bool altPressed = false;
     197    static uint8 special = 0;
     198    static uint8 special2 = 0;
     199    uint8 key = 0;
     200
     201    if (special & 0x80) {
     202        special &= ~0x80;
     203        return '[';
     204    }
     205    if (special != 0) {
     206        key = special;
     207        special = 0;
     208        return key;
     209    }
     210    if (special2 != 0) {
     211        key = special2;
     212        special2 = 0;
     213        return key;
     214    }
     215
     216    while (true) {
     217        uint8 status = in8(PS2_PORT_CTRL);
     218
     219        if ((status & PS2_STATUS_OUTPUT_BUFFER_FULL) == 0) {
     220            // no data in keyboard buffer
     221            spin(200);
     222            continue;
     223        }
     224
     225        spin(200);
     226        key = in8(PS2_PORT_DATA);
     227
     228        if (status & PS2_STATUS_AUX_DATA) {
     229            // we read mouse data, ignore it
     230            continue;
     231        }
     232
     233        if (key & 0x80) {
     234            // key up
     235            switch (key & ~0x80) {
     236                case LEFT_SHIFT:
     237                case RIGHT_SHIFT:
     238                    shiftPressed = false;
     239                    break;
     240                case LEFT_CONTROL:
     241                    controlPressed = false;
     242                    break;
     243                case LEFT_ALT:
     244                    altPressed = false;
     245                    break;
     246            }
     247        } else {
     248            // key down
     249            switch (key) {
     250                case LEFT_SHIFT:
     251                case RIGHT_SHIFT:
     252                    shiftPressed = true;
     253                    break;
     254
     255                case LEFT_CONTROL:
     256                    controlPressed = true;
     257                    break;
     258
     259                case LEFT_ALT:
     260                    altPressed = true;
     261                    break;
     262
     263                // start escape sequence for cursor movement
     264                case CURSOR_UP:
     265                    special = 0x80 | 'A';
     266                    return '\x1b';
     267                case CURSOR_DOWN:
     268                    special = 0x80 | 'B';
     269                    return '\x1b';
     270                case CURSOR_RIGHT:
     271                    special = 0x80 | 'C';
     272                    return '\x1b';
     273                case CURSOR_LEFT:
     274                    special = 0x80 | 'D';
     275                    return '\x1b';
     276                case CURSOR_HOME:
     277                    special = 0x80 | 'H';
     278                    return '\x1b';
     279                case CURSOR_END:
     280                    special = 0x80 | 'F';
     281                    return '\x1b';
     282                case PAGE_UP:
     283                    special = 0x80 | '5';
     284                    special2 = '~';
     285                    return '\x1b';
     286                case PAGE_DOWN:
     287                    special = 0x80 | '6';
     288                    special2 = '~';
     289                    return '\x1b';
     290
     291
     292                case DELETE:
     293                    if (controlPressed && altPressed)
     294                        arch_cpu_shutdown(true);
     295
     296                    special = 0x80 | '3';
     297                    special2 = '~';
     298                    return '\x1b';
     299
     300                default:
     301                    if (controlPressed) {
     302                        char c = kShiftedKeymap[key];
     303                        if (c >= 'A' && c <= 'Z')
     304                            return 0x1f & c;
     305                    }
     306
     307                    if (altPressed)
     308                        return kAltedKeymap[key];
     309
     310                    return shiftPressed
     311                        ? kShiftedKeymap[key] : kUnshiftedKeymap[key];
     312            }
     313        }
     314    }
     315}
     316
     317
     318char
     319arch_debug_serial_getchar(void)
     320{
     321    while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x1) == 0)
     322        asm volatile ("pause;");
     323
     324    return in8(sSerialBasePort + SERIAL_RECEIVE_BUFFER);
     325}
     326
     327
     328void
     329arch_debug_serial_putchar(const char c)
     330{
     331    cpu_status state = 0;
     332    if (!debug_debugger_running()) {
     333        state = disable_interrupts();
     334        acquire_spinlock(&sSerialOutputSpinlock);
     335    }
     336
     337    _arch_debug_serial_putchar(c);
     338
     339    if (!debug_debugger_running()) {
     340        release_spinlock(&sSerialOutputSpinlock);
     341        restore_interrupts(state);
     342    }
     343}
     344
     345
     346void
     347arch_debug_serial_puts(const char *s)
     348{
     349    cpu_status state = 0;
     350    if (!debug_debugger_running()) {
     351        state = disable_interrupts();
     352        acquire_spinlock(&sSerialOutputSpinlock);
     353    }
     354
     355    while (*s != '\0') {
     356        _arch_debug_serial_putchar(*s);
     357        s++;
     358    }
     359
     360    if (!debug_debugger_running()) {
     361        release_spinlock(&sSerialOutputSpinlock);
     362        restore_interrupts(state);
     363    }
     364}
     365
     366
     367void
     368arch_debug_serial_early_boot_message(const char *string)
     369{
     370    // this function will only be called in fatal situations
     371    // ToDo: also enable output via text console?!
     372    arch_debug_console_init(NULL);
     373    arch_debug_serial_puts(string);
     374}
     375
     376
     377status_t
     378arch_debug_console_init(kernel_args *args)
     379{
     380    uint16 divisor = (uint16)(115200 / kSerialBaudRate);
     381
     382    // only use the port if we could find one, else use the standard port
     383    if (args != NULL && args->platform_args.serial_base_ports[0] != 0)
     384        sSerialBasePort = args->platform_args.serial_base_ports[0];
     385
     386    out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);  /* set divisor latch access bit */
     387    out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
     388    out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
     389    out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);     /* 8N1 */
     390
     391    return B_OK;
     392}
     393
     394
     395status_t
     396arch_debug_console_init_settings(kernel_args *args)
     397{
     398    uint32 baudRate = kSerialBaudRate;
     399    uint16 basePort = sSerialBasePort;
     400    uint16 divisor;
     401    void *handle;
     402
     403    // get debug settings
     404    handle = load_driver_settings("kernel");
     405    if (handle != NULL) {
     406        const char *value = get_driver_parameter(handle, "serial_debug_port",
     407            NULL, NULL);
     408        if (value != NULL) {
     409            int32 number = strtol(value, NULL, 0);
     410            if (number >= MAX_SERIAL_PORTS) {
     411                // use as port number directly
     412                basePort = number;
     413            } else if (number >= 0) {
     414                // use as index into port array
     415                if (args->platform_args.serial_base_ports[number] != 0)
     416                    basePort = args->platform_args.serial_base_ports[number];
     417            } else {
     418                // ignore value and use default
     419            }
     420        }
     421
     422        value = get_driver_parameter(handle, "serial_debug_speed", NULL, NULL);
     423        if (value != NULL) {
     424            int32 number = strtol(value, NULL, 0);
     425            switch (number) {
     426                case 9600:
     427                case 19200:
     428                case 38400:
     429                case 57600:
     430                case 115200:
     431                //case 230400:
     432                    baudRate = number;
     433            }
     434        }
     435
     436        unload_driver_settings(handle);
     437    }
     438
     439    if (sSerialBasePort == basePort && baudRate == kSerialBaudRate)
     440        return B_OK;
     441
     442    sSerialBasePort = basePort;
     443    divisor = (uint16)(115200 / baudRate);
     444
     445    out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);  /* set divisor latch access bit */
     446    out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
     447    out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
     448    out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);     /* 8N1 */
     449
     450    return B_OK;
     451}
     452
  • src/system/kernel/arch/x86_64/asm_offsets.cpp

     
     1/*
     2 * Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6// This file is used to get C structure offsets into assembly code.
     7// The build system assembles the file and processes the output to create
     8// a header file with macro definitions, that can be included from assembly
     9// code.
     10
     11
     12#include <computed_asm_macros.h>
     13
     14#include <cpu.h>
     15#include <ksyscalls.h>
     16#include <thread_types.h>
     17
     18
     19#define DEFINE_MACRO(macro, value) DEFINE_COMPUTED_ASM_MACRO(macro, value)
     20
     21#define DEFINE_OFFSET_MACRO(prefix, structure, member) \
     22    DEFINE_MACRO(prefix##_##member, offsetof(struct structure, member));
     23
     24#define DEFINE_SIZEOF_MACRO(prefix, structure) \
     25    DEFINE_MACRO(prefix##_sizeof, sizeof(struct structure));
     26
     27
     28void
     29dummy()
     30{
     31    // struct thread
     32    DEFINE_OFFSET_MACRO(THREAD, thread, kernel_time);
     33    DEFINE_OFFSET_MACRO(THREAD, thread, user_time);
     34    DEFINE_OFFSET_MACRO(THREAD, thread, last_time);
     35    DEFINE_OFFSET_MACRO(THREAD, thread, in_kernel);
     36    DEFINE_OFFSET_MACRO(THREAD, thread, flags);
     37    DEFINE_OFFSET_MACRO(THREAD, thread, kernel_stack_top);
     38    DEFINE_OFFSET_MACRO(THREAD, thread, fault_handler);
     39
     40    // struct iframe
     41    DEFINE_OFFSET_MACRO(IFRAME, iframe, cs);
     42    DEFINE_OFFSET_MACRO(IFRAME, iframe, rax);
     43    DEFINE_OFFSET_MACRO(IFRAME, iframe, rdx);
     44    DEFINE_OFFSET_MACRO(IFRAME, iframe, orig_rax);
     45    DEFINE_OFFSET_MACRO(IFRAME, iframe, vector);
     46    DEFINE_OFFSET_MACRO(IFRAME, iframe, rip);
     47    DEFINE_OFFSET_MACRO(IFRAME, iframe, flags);
     48    DEFINE_OFFSET_MACRO(IFRAME, iframe, user_rsp);
     49
     50    // struct syscall_info
     51    DEFINE_SIZEOF_MACRO(SYSCALL_INFO, syscall_info);
     52    DEFINE_OFFSET_MACRO(SYSCALL_INFO, syscall_info, function);
     53    DEFINE_OFFSET_MACRO(SYSCALL_INFO, syscall_info, parameter_size);
     54
     55    // struct x86_optimized_functions
     56    DEFINE_OFFSET_MACRO(X86_64_OPTIMIZED_FUNCTIONS, x86_64_optimized_functions,
     57        memcpy);
     58    DEFINE_OFFSET_MACRO(X86_64_OPTIMIZED_FUNCTIONS, x86_64_optimized_functions,
     59        memset);
     60}
  • src/system/kernel/arch/x86_64/apic.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2010, Michael Lotz, mmlr@mlotz.ch. All rights reserved.
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     9 * Distributed under the terms of the MIT License.
     10 *
     11 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     12 * Distributed under the terms of the NewOS License.
     13 */
     14
     15#include <arch/x86_64/apic.h>
     16
     17#include <debug.h>
     18#include <vm/vm.h>
     19
     20#include "timers/apic_timer.h"
     21
     22
     23static void *sLocalAPIC = NULL;
     24
     25
     26bool
     27apic_available()
     28{
     29    return sLocalAPIC != NULL;
     30}
     31
     32
     33uint32
     34apic_read(uint32 offset)
     35{
     36    return *(volatile uint32 *)((char *)sLocalAPIC + offset);
     37}
     38
     39
     40void
     41apic_write(uint32 offset, uint32 data)
     42{
     43    *(volatile uint32 *)((char *)sLocalAPIC + offset) = data;
     44}
     45
     46
     47uint32
     48apic_local_id()
     49{
     50    return (apic_read(APIC_ID) & 0xffffffff) >> 24;
     51}
     52
     53
     54void
     55apic_end_of_interrupt()
     56{
     57    apic_write(APIC_EOI, 0);
     58}
     59
     60
     61status_t
     62apic_init(kernel_args *args)
     63{
     64    if (args->arch_args.apic == NULL)
     65        return B_NO_INIT;
     66
     67    sLocalAPIC = args->arch_args.apic;
     68    dprintf("mapping local apic at %p\n", sLocalAPIC);
     69    if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC,
     70            B_EXACT_ADDRESS, B_PAGE_SIZE,
     71            B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
     72            args->arch_args.apic_phys, true) < 0) {
     73        panic("mapping the local apic failed");
     74        return B_ERROR;
     75    }
     76
     77    return B_OK;
     78}
     79
     80
     81status_t
     82apic_per_cpu_init(kernel_args *args, int32 cpu)
     83{
     84    dprintf("setting up apic for CPU %ld: apic id %lu, version %lu\n", cpu,
     85        apic_local_id(), apic_read(APIC_VERSION));
     86
     87    /* set spurious interrupt vector to 0xff */
     88    uint32 config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00;
     89    config |= APIC_ENABLE | 0xff;
     90    apic_write(APIC_SPURIOUS_INTR_VECTOR, config);
     91
     92
     93    apic_timer_per_cpu_init(args, cpu);
     94
     95    /* setup error vector to 0xfe */
     96    config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe;
     97    apic_write(APIC_LVT_ERROR, config);
     98
     99    /* accept all interrupts */
     100    config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00;
     101    apic_write(APIC_TASK_PRIORITY, config);
     102
     103    config = apic_read(APIC_SPURIOUS_INTR_VECTOR);
     104    apic_end_of_interrupt();
     105
     106    return B_OK;
     107}
  • src/system/kernel/arch/x86_64/arch_timer.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     9 * Distributed under the terms of the NewOS License.
     10 */
     11
     12
     13#include <boot/stage2.h>
     14#include <kernel.h>
     15
     16#include <arch/int.h>
     17#include <arch/cpu.h>
     18
     19#include <console.h>
     20#include <debug.h>
     21#include <timer.h>
     22#include <int.h>
     23#include <safemode.h>
     24
     25#include <arch/timer.h>
     26
     27
     28//#define TRACE_TIMER
     29#ifdef TRACE_TIMER
     30#   define TRACE(x) dprintf x
     31#else
     32#   define TRACE(x) ;
     33#endif
     34
     35extern timer_info gPITTimer;
     36extern timer_info gAPICTimer;
     37extern timer_info gHPETTimer;
     38
     39static timer_info *sTimers[] = {
     40    &gHPETTimer,
     41    &gAPICTimer,
     42    &gPITTimer,
     43    NULL
     44};
     45
     46static timer_info *sTimer = NULL;
     47
     48
     49static void
     50sort_timers(timer_info *timers[], int numTimers)
     51{
     52    timer_info *tempPtr;
     53    int max = 0;   
     54    int i = 0;
     55    int j = 0;
     56   
     57    for (i = 0; i < numTimers - 1; i++) {
     58        max = i;
     59        for (j = i + 1; j < numTimers; j++) {
     60            if (timers[j]->get_priority() > timers[max]->get_priority())
     61                max = j;
     62        }
     63        if (max != i) {
     64            tempPtr = timers[max];
     65            timers[max] = timers[i];
     66            timers[i] = tempPtr;       
     67        }
     68    }
     69}
     70
     71
     72void
     73arch_timer_set_hardware_timer(bigtime_t timeout)
     74{
     75    TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout));
     76    sTimer->set_hardware_timer(timeout);
     77}
     78
     79
     80void
     81arch_timer_clear_hardware_timer()
     82{
     83    TRACE(("arch_timer_clear_hardware_timer\n"));
     84    sTimer->clear_hardware_timer();
     85}
     86
     87
     88int
     89arch_init_timer(kernel_args *args)
     90{
     91    // Sort timers by priority
     92    sort_timers(sTimers, (sizeof(sTimers) / sizeof(sTimers[0])) - 1);
     93
     94    timer_info *timer = NULL;
     95    cpu_status state = disable_interrupts();
     96   
     97    for (int i = 0; (timer = sTimers[i]) != NULL; i++) {
     98        if (timer->init(args) == B_OK)
     99            break;
     100    }
     101
     102    sTimer = timer;
     103
     104    if (sTimer != NULL) {
     105        dprintf("arch_init_timer: using %s timer.\n", sTimer->name);
     106    } else {
     107        panic("No system timers were found usable.\n");
     108    }
     109
     110    restore_interrupts(state);
     111
     112    return 0;
     113}
     114
  • src/system/kernel/arch/x86_64/irq_routing_table.h

     
     1/*
     2 * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de.
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef IRQ_ROUTING_TABLE_H
     6#define IRQ_ROUTING_TABLE_H
     7
     8
     9#include <ACPI.h>
     10#include <PCI.h>
     11
     12
     13#include "util/Vector.h"
     14
     15
     16struct irq_routing_entry {
     17    int             device_address;
     18    int8            pin;
     19
     20    acpi_handle     source;
     21    int             source_index;
     22
     23    // pci busmanager connection
     24    uchar           pci_bus;
     25    uchar           pci_device;
     26};
     27
     28
     29typedef Vector<irq_routing_entry> IRQRoutingTable;
     30
     31
     32struct irq_descriptor {
     33    irq_descriptor();
     34    // bit 0 is interrupt 0, bit 2 is interrupt 2, and so on
     35    int16           irq;
     36    bool            shareable;
     37    // B_LOW_ACTIVE_POLARITY or B_HIGH_ACTIVE_POLARITY
     38    int8            polarity;
     39    // B_LEVEL_TRIGGERED or B_EDGE_TRIGGERED
     40    int8            interrupt_mode;
     41};
     42
     43
     44// Similar to bus_managers/acpi/include/acrestyp.h definition
     45typedef struct acpi_prt {
     46    uint32          length;
     47    uint32          pin;
     48    int             address;        // here for 64-bit alignment
     49    uint32          sourceIndex;
     50    char            source[4];      // pad to 64 bits so sizeof() works in
     51                                    // all cases
     52} acpi_pci_routing_table;
     53
     54
     55void print_irq_descriptor(irq_descriptor* descriptor);
     56void print_irq_routing_table(IRQRoutingTable* table);
     57
     58
     59status_t read_irq_routing_table(pci_module_info *pci, acpi_module_info* acpi,
     60            IRQRoutingTable* table);
     61status_t read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
     62            const char* method, irq_descriptor* descriptor);
     63
     64status_t read_current_irq(acpi_module_info* acpi, acpi_handle device,
     65            irq_descriptor* descriptor);
     66status_t read_possible_irq(acpi_module_info* acpi, acpi_handle device,
     67            irq_descriptor* descriptor);
     68
     69status_t set_acpi_irq(acpi_module_info* acpi, acpi_handle device,
     70            irq_descriptor* descriptor);
     71
     72#endif  // IRQ_ROUTING_TABLE_H
  • src/system/kernel/arch/x86_64/arch_vm.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Copyright 2008, Jérôme Duval.
     5 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de.
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     9 * Distributed under the terms of the NewOS License.
     10 */
     11
     12
     13#include <stdlib.h>
     14#include <string.h>
     15
     16#include <algorithm>
     17#include <new>
     18
     19#include <KernelExport.h>
     20
     21#include <boot/kernel_args.h>
     22#include <smp.h>
     23#include <util/AutoLock.h>
     24#include <vm/vm.h>
     25#include <vm/vm_page.h>
     26#include <vm/vm_priv.h>
     27#include <vm/VMAddressSpace.h>
     28#include <vm/VMArea.h>
     29
     30#include <arch/vm.h>
     31#include <arch/int.h>
     32#include <arch/cpu.h>
     33
     34
     35//#define TRACE_ARCH_VM
     36#ifdef TRACE_ARCH_VM
     37#   define TRACE(x) dprintf x
     38#else
     39#   define TRACE(x) ;
     40#endif
     41
     42// 0: disabled, 1: some, 2: more
     43#define TRACE_MTRR_ARCH_VM 0
     44
     45#if TRACE_MTRR_ARCH_VM >= 1
     46#   define TRACE_MTRR(x...) dprintf(x)
     47#else
     48#   define TRACE_MTRR(x...)
     49#endif
     50
     51#if TRACE_MTRR_ARCH_VM >= 2
     52#   define TRACE_MTRR2(x...) dprintf(x)
     53#else
     54#   define TRACE_MTRR2(x...)
     55#endif
     56
     57void *gDmaAddress;
     58
     59
     60struct memory_type_range : DoublyLinkedListLinkImpl<memory_type_range> {
     61    uint64                      base;
     62    uint64                      size;
     63    uint32                      type;
     64    area_id                     area;
     65};
     66
     67
     68struct memory_type_range_point
     69        : DoublyLinkedListLinkImpl<memory_type_range_point> {
     70    uint64              address;
     71    memory_type_range*  range;
     72
     73    bool IsStart() const    { return range->base == address; }
     74
     75    bool operator<(const memory_type_range_point& other) const
     76    {
     77        return address < other.address;
     78    }
     79};
     80
     81
     82struct update_mtrr_info {
     83    uint64  ignoreUncacheableSize;
     84    uint64  shortestUncacheableSize;
     85};
     86
     87
     88typedef DoublyLinkedList<memory_type_range> MemoryTypeRangeList;
     89
     90static mutex sMemoryTypeLock = MUTEX_INITIALIZER("memory type ranges");
     91static MemoryTypeRangeList sMemoryTypeRanges;
     92static int32 sMemoryTypeRangeCount = 0;
     93
     94static const uint32 kMaxMemoryTypeRegisters = 32;
     95static x86_64_mtrr_info sMemoryTypeRegisters[kMaxMemoryTypeRegisters];
     96static uint32 sMemoryTypeRegisterCount;
     97static uint32 sMemoryTypeRegistersUsed;
     98
     99static memory_type_range* sTemporaryRanges = NULL;
     100static memory_type_range_point* sTemporaryRangePoints = NULL;
     101static int32 sTemporaryRangeCount = 0;
     102static int32 sTemporaryRangePointCount = 0;
     103
     104
     105
     106static void
     107set_mtrrs()
     108{
     109    x86_64_set_mtrrs(IA32_MTR_WRITE_BACK, sMemoryTypeRegisters,
     110        sMemoryTypeRegistersUsed);
     111
     112#if TRACE_MTRR_ARCH_VM
     113    TRACE_MTRR("set MTRRs to:\n");
     114    for (uint32 i = 0; i < sMemoryTypeRegistersUsed; i++) {
     115        const x86_64_mtrr_info& info = sMemoryTypeRegisters[i];
     116        TRACE_MTRR("  mtrr: %2" B_PRIu32 ": base: %#10" B_PRIx64  ", size: %#10"
     117            B_PRIx64 ", type: %u\n", i, info.base, info.size,
     118            info.type);
     119    }
     120#endif
     121}
     122
     123
     124static bool
     125add_used_mtrr(uint64 base, uint64 size, uint32 type)
     126{
     127    if (sMemoryTypeRegistersUsed == sMemoryTypeRegisterCount)
     128        return false;
     129
     130    x86_64_mtrr_info& mtrr = sMemoryTypeRegisters[sMemoryTypeRegistersUsed++];
     131    mtrr.base = base;
     132    mtrr.size = size;
     133    mtrr.type = type;
     134
     135    return true;
     136}
     137
     138
     139static bool
     140ensure_temporary_ranges_space(int32 count)
     141{
     142    if (sTemporaryRangeCount >= count && sTemporaryRangePointCount >= count)
     143        return true;
     144
     145    // round count to power of 2
     146    int32 unalignedCount = count;
     147    count = 8;
     148    while (count < unalignedCount)
     149        count <<= 1;
     150
     151    // resize ranges array
     152    if (sTemporaryRangeCount < count) {
     153        memory_type_range* ranges = new(std::nothrow) memory_type_range[count];
     154        if (ranges == NULL)
     155            return false;
     156
     157        delete[] sTemporaryRanges;
     158
     159        sTemporaryRanges = ranges;
     160        sTemporaryRangeCount = count;
     161    }
     162
     163    // resize points array
     164    if (sTemporaryRangePointCount < count) {
     165        memory_type_range_point* points
     166            = new(std::nothrow) memory_type_range_point[count];
     167        if (points == NULL)
     168            return false;
     169
     170        delete[] sTemporaryRangePoints;
     171
     172        sTemporaryRangePoints = points;
     173        sTemporaryRangePointCount = count;
     174    }
     175
     176    return true;
     177}
     178
     179
     180static bool
     181add_mtrrs_for_range(uint64 base, uint64 size, uint32 type)
     182{
     183    for (uint64 interval = B_PAGE_SIZE; size > 0; interval <<= 1) {
     184        if ((base & interval) != 0) {
     185            if (!add_used_mtrr(base, interval, type))
     186                return false;
     187            base += interval;
     188            size -= interval;
     189        }
     190
     191        if ((size & interval) != 0) {
     192            if (!add_used_mtrr(base + size - interval, interval, type))
     193                return false;
     194            size -= interval;
     195        }
     196    }
     197
     198    return true;
     199}
     200
     201
     202static memory_type_range*
     203find_range(area_id areaID)
     204{
     205    for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator();
     206            memory_type_range* range = it.Next();) {
     207        if (range->area == areaID)
     208            return range;
     209    }
     210
     211    return NULL;
     212}
     213
     214
     215static void
     216optimize_memory_ranges(MemoryTypeRangeList& ranges, uint32 type,
     217    bool removeRanges)
     218{
     219    uint64 previousEnd = 0;
     220    uint64 nextStart = 0;
     221    MemoryTypeRangeList::Iterator it = ranges.GetIterator();
     222    memory_type_range* range = it.Next();
     223    while (range != NULL) {
     224        if (range->type != type) {
     225            previousEnd = range->base + range->size;
     226            nextStart = 0;
     227            range = it.Next();
     228            continue;
     229        }
     230
     231        // find the start of the next range we cannot join this one with
     232        if (nextStart == 0) {
     233            MemoryTypeRangeList::Iterator nextIt = it;
     234            while (memory_type_range* nextRange = nextIt.Next()) {
     235                if (nextRange->type != range->type) {
     236                    nextStart = nextRange->base;
     237                    break;
     238                }
     239            }
     240
     241            if (nextStart == 0) {
     242                // no upper limit -- set an artificial one, so we don't need to
     243                // special case below
     244                nextStart = (uint64)1 << 32;
     245            }
     246        }
     247
     248        // Align the range's base and end to the greatest power of two possible.
     249        // As long as we can align both without intersecting any differently
     250        // range, we can extend the range without making it more complicated.
     251        // Once one side hit a limit we need to be careful. We can still
     252        // continue aligning the other side, if the range crosses the power of
     253        // two boundary.
     254        uint64 rangeBase = range->base;
     255        uint64 rangeEnd = rangeBase + range->size;
     256        uint64 interval = B_PAGE_SIZE * 2;
     257        while (true) {
     258            uint64 alignedBase = rangeBase & ~(interval - 1);
     259            uint64 alignedEnd = (rangeEnd + interval - 1) & ~(interval - 1);
     260
     261            if (alignedBase < previousEnd)
     262                alignedBase += interval;
     263
     264            if (alignedEnd > nextStart)
     265                alignedEnd -= interval;
     266
     267            if (alignedBase >= alignedEnd)
     268                break;
     269
     270            rangeBase = std::min(rangeBase, alignedBase);
     271            rangeEnd = std::max(rangeEnd, alignedEnd);
     272
     273            interval <<= 1;
     274        }
     275
     276        range->base = rangeBase;
     277        range->size = rangeEnd - rangeBase;
     278
     279        if (removeRanges)
     280            it.Remove();
     281
     282        previousEnd = rangeEnd;
     283
     284        // Skip the subsequent ranges we have swallowed and possible cut one
     285        // we now partially intersect with.
     286        while ((range = it.Next()) != NULL) {
     287            if (range->base >= rangeEnd)
     288                break;
     289
     290            if (range->base + range->size > rangeEnd) {
     291                // we partially intersect -- cut the range
     292                range->size = range->base + range->size - rangeEnd;
     293                range->base = rangeEnd;
     294                break;
     295            }
     296
     297            // we have swallowed this range completely
     298            range->size = 0;
     299            it.Remove();
     300        }
     301    }
     302}
     303
     304
     305status_t
     306update_mtrrs(update_mtrr_info& updateInfo)
     307{
     308    // resize the temporary points/ranges arrays, if necessary
     309    if (!ensure_temporary_ranges_space(sMemoryTypeRangeCount * 2))
     310        return B_NO_MEMORY;
     311
     312    // get the range points and sort them
     313    memory_type_range_point* rangePoints = sTemporaryRangePoints;
     314    int32 pointCount = 0;
     315    for (MemoryTypeRangeList::Iterator it = sMemoryTypeRanges.GetIterator();
     316            memory_type_range* range = it.Next();) {
     317        if (range->type == IA32_MTR_UNCACHED) {
     318            // Ignore uncacheable ranges below a certain size, if requested.
     319            // Since we always enforce uncacheability via the PTE attributes,
     320            // this is no problem (though not recommended for performance
     321            // reasons).
     322            if (range->size <= updateInfo.ignoreUncacheableSize)
     323                continue;
     324            if (range->size < updateInfo.shortestUncacheableSize)
     325                updateInfo.shortestUncacheableSize = range->size;
     326        }
     327
     328        rangePoints[pointCount].address = range->base;
     329        rangePoints[pointCount++].range = range;
     330        rangePoints[pointCount].address = range->base + range->size;
     331        rangePoints[pointCount++].range = range;
     332    }
     333
     334    std::sort(rangePoints, rangePoints + pointCount);
     335
     336#if TRACE_MTRR_ARCH_VM >= 2
     337    TRACE_MTRR2("memory type range points:\n");
     338    for (int32 i = 0; i < pointCount; i++) {
     339        TRACE_MTRR2("%12" B_PRIx64 " (%p)\n", rangePoints[i].address,
     340            rangePoints[i].range);
     341    }
     342#endif
     343
     344    // Compute the effective ranges. When ranges overlap, we go with the
     345    // stricter requirement. The types are not necessarily totally ordered, so
     346    // the order we use below is not always correct. To keep it simple we
     347    // consider it the reponsibility of the callers not to define overlapping
     348    // memory ranges with uncomparable types.
     349
     350    memory_type_range* ranges = sTemporaryRanges;
     351    typedef DoublyLinkedList<memory_type_range_point> PointList;
     352    PointList pendingPoints;
     353    memory_type_range* activeRange = NULL;
     354    int32 rangeCount = 0;
     355
     356    for (int32 i = 0; i < pointCount; i++) {
     357        memory_type_range_point* point = &rangePoints[i];
     358        bool terminateRange = false;
     359        if (point->IsStart()) {
     360            // a range start point
     361            pendingPoints.Add(point);
     362            if (activeRange != NULL && activeRange->type > point->range->type)
     363                terminateRange = true;
     364        } else {
     365            // a range end point -- remove the pending start point
     366            for (PointList::Iterator it = pendingPoints.GetIterator();
     367                    memory_type_range_point* pendingPoint = it.Next();) {
     368                if (pendingPoint->range == point->range) {
     369                    it.Remove();
     370                    break;
     371                }
     372            }
     373
     374            if (point->range == activeRange)
     375                terminateRange = true;
     376        }
     377
     378        if (terminateRange) {
     379            ranges[rangeCount].size = point->address - ranges[rangeCount].base;
     380            rangeCount++;
     381            activeRange = NULL;
     382        }
     383
     384        if (activeRange != NULL || pendingPoints.IsEmpty())
     385            continue;
     386
     387        // we need to start a new range -- find the strictest pending range
     388        for (PointList::Iterator it = pendingPoints.GetIterator();
     389                memory_type_range_point* pendingPoint = it.Next();) {
     390            memory_type_range* pendingRange = pendingPoint->range;
     391            if (activeRange == NULL || activeRange->type > pendingRange->type)
     392                activeRange = pendingRange;
     393        }
     394
     395        memory_type_range* previousRange = rangeCount > 0
     396            ? &ranges[rangeCount - 1] : NULL;
     397        if (previousRange == NULL || previousRange->type != activeRange->type
     398                || previousRange->base + previousRange->size
     399                    < activeRange->base) {
     400            // we can't join with the previous range -- add a new one
     401            ranges[rangeCount].base = point->address;
     402            ranges[rangeCount].type = activeRange->type;
     403        } else
     404            rangeCount--;
     405    }
     406
     407#if TRACE_MTRR_ARCH_VM >= 2
     408    TRACE_MTRR2("effective memory type ranges:\n");
     409    for (int32 i = 0; i < rangeCount; i++) {
     410        TRACE_MTRR2("%12" B_PRIx64 " - %12" B_PRIx64 ": %" B_PRIu32 "\n",
     411            ranges[i].base, ranges[i].base + ranges[i].size, ranges[i].type);
     412    }
     413#endif
     414
     415    // Extend ranges to be more MTRR-friendly. A range is MTRR friendly, when it
     416    // has a power of two size and a base address aligned to the size. For
     417    // ranges without this property we need more than one MTRR. We improve
     418    // MTRR-friendliness by aligning a range's base and end address to the
     419    // greatest power of two (base rounded down, end up) such that the extended
     420    // range does not intersect with any other differently typed range. We join
     421    // equally typed ranges, if possible. There are two exceptions to the
     422    // intersection requirement: Uncached ranges may intersect with any other
     423    // range; the resulting type will still be uncached. Hence we can ignore
     424    // uncached ranges when extending the other ranges. Write-through ranges may
     425    // intersect with write-back ranges; the resulting type will be
     426    // write-through. Hence we can ignore write-through ranges when extending
     427    // write-back ranges.
     428
     429    MemoryTypeRangeList rangeList;
     430    for (int32 i = 0; i < rangeCount; i++)
     431        rangeList.Add(&ranges[i]);
     432
     433    static const uint32 kMemoryTypes[] = {
     434        IA32_MTR_UNCACHED,
     435        IA32_MTR_WRITE_COMBINING,
     436        IA32_MTR_WRITE_PROTECTED,
     437        IA32_MTR_WRITE_THROUGH,
     438        IA32_MTR_WRITE_BACK
     439    };
     440    static const int32 kMemoryTypeCount = sizeof(kMemoryTypes)
     441        / sizeof(*kMemoryTypes);
     442
     443    for (int32 i = 0; i < kMemoryTypeCount; i++) {
     444        uint32 type = kMemoryTypes[i];
     445
     446        // Remove uncached and write-through ranges after processing them. This
     447        // let's us leverage their intersection property with any other
     448        // respectively write-back ranges.
     449        bool removeRanges = type == IA32_MTR_UNCACHED
     450            || type == IA32_MTR_WRITE_THROUGH;
     451
     452        optimize_memory_ranges(rangeList, type, removeRanges);
     453    }
     454
     455#if TRACE_MTRR_ARCH_VM >= 2
     456    TRACE_MTRR2("optimized memory type ranges:\n");
     457    for (int32 i = 0; i < rangeCount; i++) {
     458        if (ranges[i].size > 0) {
     459            TRACE_MTRR2("%12" B_PRIx64 " - %12" B_PRIx64 ": %" B_PRIu32 "\n",
     460                ranges[i].base, ranges[i].base + ranges[i].size,
     461                ranges[i].type);
     462        }
     463    }
     464#endif
     465
     466    // compute the mtrrs from the ranges
     467    sMemoryTypeRegistersUsed = 0;
     468    for (int32 i = 0; i < kMemoryTypeCount; i++) {
     469        uint32 type = kMemoryTypes[i];
     470
     471        // skip write-back ranges -- that'll be the default type anyway
     472        if (type == IA32_MTR_WRITE_BACK)
     473            continue;
     474
     475        for (int32 i = 0; i < rangeCount; i++) {
     476            if (ranges[i].size == 0 || ranges[i].type != type)
     477                continue;
     478
     479            if (!add_mtrrs_for_range(ranges[i].base, ranges[i].size, type))
     480                return B_BUSY;
     481        }
     482    }
     483
     484    set_mtrrs();
     485
     486    return B_OK;
     487}
     488
     489
     490status_t
     491update_mtrrs()
     492{
     493    // Until we know how many MTRRs we have, pretend everything is OK.
     494    if (sMemoryTypeRegisterCount == 0)
     495        return B_OK;
     496
     497    update_mtrr_info updateInfo;
     498    updateInfo.ignoreUncacheableSize = 0;
     499
     500    while (true) {
     501        TRACE_MTRR2("update_mtrrs(): Trying with ignoreUncacheableSize %#"
     502            B_PRIx64 ".\n", updateInfo.ignoreUncacheableSize);
     503
     504        updateInfo.shortestUncacheableSize = ~(uint64)0;
     505        status_t error = update_mtrrs(updateInfo);
     506        if (error != B_BUSY) {
     507            if (error == B_OK && updateInfo.ignoreUncacheableSize > 0) {
     508                TRACE_MTRR("update_mtrrs(): Succeeded setting MTRRs after "
     509                    "ignoring uncacheable ranges up to size %#" B_PRIx64 ".\n",
     510                    updateInfo.ignoreUncacheableSize);
     511            }
     512            return error;
     513        }
     514
     515        // Not enough MTRRs. Retry with less uncacheable ranges.
     516        if (updateInfo.shortestUncacheableSize == ~(uint64)0) {
     517            // Ugh, even without any uncacheable ranges the available MTRRs do
     518            // not suffice.
     519            panic("update_mtrrs(): Out of MTRRs!");
     520            return B_BUSY;
     521        }
     522
     523        ASSERT(updateInfo.ignoreUncacheableSize
     524            < updateInfo.shortestUncacheableSize);
     525
     526        updateInfo.ignoreUncacheableSize = updateInfo.shortestUncacheableSize;
     527    }
     528}
     529
     530
     531static status_t
     532add_memory_type_range(area_id areaID, uint64 base, uint64 size, uint32 type)
     533{
     534    // translate the type
     535    if (type == 0)
     536        return B_OK;
     537
     538    switch (type) {
     539        case B_MTR_UC:
     540            type = IA32_MTR_UNCACHED;
     541            break;
     542        case B_MTR_WC:
     543            type = IA32_MTR_WRITE_COMBINING;
     544            break;
     545        case B_MTR_WT:
     546            type = IA32_MTR_WRITE_THROUGH;
     547            break;
     548        case B_MTR_WP:
     549            type = IA32_MTR_WRITE_PROTECTED;
     550            break;
     551        case B_MTR_WB:
     552            type = IA32_MTR_WRITE_BACK;
     553            break;
     554        default:
     555            return B_BAD_VALUE;
     556    }
     557
     558    TRACE_MTRR("add_memory_type_range(%" B_PRId32 ", %#" B_PRIx64 ", %#"
     559        B_PRIx64 ", %" B_PRIu32 ")\n", areaID, base, size, type);
     560
     561    MutexLocker locker(sMemoryTypeLock);
     562
     563    memory_type_range* range = areaID >= 0 ? find_range(areaID) : NULL;
     564    int32 oldRangeType = -1;
     565    if (range != NULL) {
     566        if (range->base != base || range->size != size)
     567            return B_BAD_VALUE;
     568        if (range->type == type)
     569            return B_OK;
     570
     571        oldRangeType = range->type;
     572        range->type = type;
     573    } else {
     574        range = new(std::nothrow) memory_type_range;
     575        if (range == NULL)
     576            return B_NO_MEMORY;
     577
     578        range->area = areaID;
     579        range->base = base;
     580        range->size = size;
     581        range->type = type;
     582        sMemoryTypeRanges.Add(range);
     583        sMemoryTypeRangeCount++;
     584    }
     585
     586    status_t error = update_mtrrs();
     587    if (error != B_OK) {
     588        // revert the addition of the range/change of its type
     589        if (oldRangeType < 0) {
     590            sMemoryTypeRanges.Remove(range);
     591            sMemoryTypeRangeCount--;
     592            delete range;
     593        } else
     594            range->type = oldRangeType;
     595
     596        update_mtrrs();
     597        return error;
     598    }
     599
     600    return B_OK;
     601}
     602
     603
     604static void
     605remove_memory_type_range(area_id areaID)
     606{
     607    MutexLocker locker(sMemoryTypeLock);
     608
     609    memory_type_range* range = find_range(areaID);
     610    if (range != NULL) {
     611        TRACE_MTRR("remove_memory_type_range(%" B_PRId32 ", %#" B_PRIx64 ", %#"
     612            B_PRIx64 ", %" B_PRIu32 ")\n", range->area, range->base,
     613            range->size, range->type);
     614
     615        sMemoryTypeRanges.Remove(range);
     616        sMemoryTypeRangeCount--;
     617        delete range;
     618
     619        update_mtrrs();
     620    } else {
     621        dprintf("remove_memory_type_range(): no range known for area %" B_PRId32
     622            "\n", areaID);
     623    }
     624}
     625
     626
     627status_t
     628arch_vm_init(kernel_args *args)
     629{
     630    TRACE(("arch_vm_init: entry\n"));
     631    return 0;
     632}
     633
     634
     635status_t
     636arch_vm_init_post_area(kernel_args *args)
     637{
     638    area_id id;
     639
     640    TRACE(("arch_vm_init_post_area: entry\n"));
     641
     642    // account for DMA area and mark the pages unusable
     643    vm_mark_page_range_inuse(0x0, 0xa0000 / B_PAGE_SIZE);
     644
     645    // map 0 - 0xa0000 directly
     646    id = map_physical_memory("dma_region", 0x0, 0xa0000,
     647        B_ANY_KERNEL_ADDRESS | B_MTR_WB,
     648        B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, &gDmaAddress);
     649    if (id < 0) {
     650        panic("arch_vm_init_post_area: unable to map dma region\n");
     651        return B_NO_MEMORY;
     652    }
     653
     654    return B_OK;
     655}
     656
     657
     658status_t
     659arch_vm_init_end(kernel_args *args)
     660{
     661    TRACE(("arch_vm_init_endvm: entry\n"));
     662
     663    // throw away anything in the kernel_args.pgtable[] that's not yet mapped
     664    vm_free_unused_boot_loader_range(KERNEL_BASE,
     665        args->arch_args.virtual_end - KERNEL_BASE);
     666
     667    return B_OK;
     668}
     669
     670
     671status_t
     672arch_vm_init_post_modules(kernel_args *args)
     673{
     674    // the x86_64 CPU modules are now accessible
     675
     676    sMemoryTypeRegisterCount = x86_64_count_mtrrs();
     677    if (sMemoryTypeRegisterCount == 0)
     678        return B_OK;
     679
     680    // not very likely, but play safe here
     681    if (sMemoryTypeRegisterCount > kMaxMemoryTypeRegisters)
     682        sMemoryTypeRegisterCount = kMaxMemoryTypeRegisters;
     683
     684    // set the physical memory ranges to write-back mode
     685    for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
     686        add_memory_type_range(-1, args->physical_memory_range[i].start,
     687            args->physical_memory_range[i].size, B_MTR_WB);
     688    }
     689
     690    return B_OK;
     691}
     692
     693
     694void
     695arch_vm_aspace_swap(struct VMAddressSpace *from, struct VMAddressSpace *to)
     696{
     697    // This functions is only invoked when a userland thread is in the process
     698    // of dying. It switches to the kernel team and does whatever cleanup is
     699    // necessary (in case it is the team's main thread, it will delete the
     700    // team).
     701    // It is however not necessary to change the page directory. Userland team's
     702    // page directories include all kernel mappings as well. Furthermore our
     703    // arch specific translation map data objects are ref-counted, so they won't
     704    // go away as long as they are still used on any CPU.
     705}
     706
     707
     708bool
     709arch_vm_supports_protection(uint32 protection)
     710{
     711    // x86 and x86_64 always has the same read/write properties for userland
     712    // and the kernel.
     713    // That's why we do not support user-read/kernel-write access. While the
     714    // other way around is not supported either, we don't care in this case
     715    // and give the kernel full access.
     716    if ((protection & (B_READ_AREA | B_WRITE_AREA)) == B_READ_AREA
     717        && (protection & B_KERNEL_WRITE_AREA) != 0) {
     718        return false;
     719    }
     720
     721    return true;
     722}
     723
     724
     725void
     726arch_vm_unset_memory_type(VMArea *area)
     727{
     728    if (area->MemoryType() == 0)
     729        return;
     730
     731    remove_memory_type_range(area->id);
     732}
     733
     734
     735status_t
     736arch_vm_set_memory_type(VMArea *area, phys_addr_t physicalBase, uint32 type)
     737{
     738    return add_memory_type_range(area->id, physicalBase, area->Size(), type);
     739}
  • src/system/kernel/arch/x86_64/arch_platform.cpp

     
     1/*
     2 * Copyright 2010, Haiku, Inc. All Rights Reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6
     7#include <arch/platform.h>
     8
     9
     10status_t
     11arch_platform_init(struct kernel_args *kernelArgs)
     12{
     13    return B_OK;
     14}
     15
     16
     17status_t
     18arch_platform_init_post_vm(struct kernel_args *kernelArgs)
     19{
     20    return B_OK;
     21}
     22
     23
     24/* TODO: x86 initalizes APM code here. x86_64 could do that as well. */
     25status_t
     26arch_platform_init_post_thread(struct kernel_args *kernelArgs)
     27{
     28    return B_OK;
     29}
  • src/system/kernel/arch/x86_64/timers/x86_64_hpet.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2009-2010, Stefano Ceccherini (stefano.ceccherini@gmail.com)
     4 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
     5 * Distributed under the terms of the MIT License.
     6 */
     7
     8#include <debug.h>
     9#include <int.h>
     10#include <smp.h>
     11#include <timer.h>
     12
     13#include <arch/int.h>
     14#include <arch/cpu.h>
     15#include <arch/x86_64/timer.h>
     16#include <arch/x86_64/arch_hpet.h>
     17
     18#include <boot/kernel_args.h>
     19#include <vm/vm.h>
     20
     21
     22//#define TRACE_HPET
     23#ifdef TRACE_HPET
     24    #define TRACE(x) dprintf x
     25#else
     26    #define TRACE(x) ;
     27#endif
     28
     29#define TEST_HPET
     30
     31static struct hpet_regs *sHPETRegs;
     32static volatile struct hpet_timer *sTimer;
     33static uint64 sHPETPeriod;
     34
     35static int hpet_get_priority();
     36static status_t hpet_set_hardware_timer(bigtime_t relativeTimeout);
     37static status_t hpet_clear_hardware_timer();
     38static status_t hpet_init(struct kernel_args *args);
     39
     40
     41struct timer_info gHPETTimer = {
     42    "HPET",
     43    &hpet_get_priority,
     44    &hpet_set_hardware_timer,
     45    &hpet_clear_hardware_timer,
     46    &hpet_init
     47};
     48
     49
     50static int
     51hpet_get_priority()
     52{
     53    // TODO: Fix HPET for SMP.
     54    if (smp_get_num_cpus() > 1)
     55        return 0;
     56
     57    // HPET timers, being off-chip, are more expensive to setup
     58    // than the LAPIC.
     59    return 0;
     60}
     61
     62
     63static int32
     64hpet_timer_interrupt(void *arg)
     65{
     66    //dprintf_no_syslog("HPET timer_interrupt!!!!\n");
     67    return timer_interrupt();
     68}
     69
     70
     71static inline bigtime_t
     72hpet_convert_timeout(const bigtime_t &relativeTimeout)
     73{
     74    return ((relativeTimeout * 1000000000ULL)
     75        / sHPETPeriod) + sHPETRegs->u0.counter64;
     76}
     77
     78
     79#define MIN_TIMEOUT 3000
     80
     81static status_t
     82hpet_set_hardware_timer(bigtime_t relativeTimeout)
     83{
     84    cpu_status state = disable_interrupts();
     85
     86    // enable timer interrupt
     87    sTimer->config |= HPET_CONF_TIMER_INT_ENABLE;
     88
     89
     90    if (relativeTimeout < MIN_TIMEOUT)
     91        relativeTimeout = MIN_TIMEOUT;
     92
     93    bigtime_t timerValue = hpet_convert_timeout(relativeTimeout);
     94
     95    sTimer->u0.comparator64 = timerValue;
     96
     97    restore_interrupts(state);
     98
     99    return B_OK;
     100}
     101
     102
     103static status_t
     104hpet_clear_hardware_timer()
     105{
     106    // Disable timer interrupt
     107    sTimer->config &= ~HPET_CONF_TIMER_INT_ENABLE;
     108    return B_OK;
     109}
     110
     111
     112static status_t
     113hpet_set_enabled(bool enabled)
     114{
     115    if (enabled)
     116        sHPETRegs->config |= HPET_CONF_MASK_ENABLED;
     117    else
     118        sHPETRegs->config &= ~HPET_CONF_MASK_ENABLED;
     119    return B_OK;
     120}
     121
     122
     123static status_t
     124hpet_set_legacy(bool enabled)
     125{
     126    if (!HPET_IS_LEGACY_CAPABLE(sHPETRegs)) {
     127        dprintf("hpet_init: HPET doesn't support legacy mode. Skipping.\n");
     128        return B_NOT_SUPPORTED;
     129    }
     130
     131    if (enabled)
     132        sHPETRegs->config |= HPET_CONF_MASK_LEGACY;
     133    else
     134        sHPETRegs->config &= ~HPET_CONF_MASK_LEGACY;
     135
     136    return B_OK;
     137}
     138
     139
     140#ifdef TRACE_HPET
     141static void
     142hpet_dump_timer(volatile struct hpet_timer *timer)
     143{
     144    dprintf("HPET Timer %ld:\n", (timer - sHPETRegs->timer));
     145
     146    dprintf("\troutable IRQs: ");
     147    uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer);
     148    for (int i = 0; i < 32; i++) {
     149        if (interrupts & (1 << i))
     150            dprintf("%d ", i);
     151    }
     152    dprintf("\n");
     153    dprintf("\tconfiguration: 0x%llx\n", timer->config);
     154    dprintf("\tFSB Enabled: %s\n",
     155        timer->config & HPET_CONF_TIMER_FSB_ENABLE ? "Yes" : "No");
     156    dprintf("\tInterrupt Enabled: %s\n",
     157        timer->config & HPET_CONF_TIMER_INT_ENABLE ? "Yes" : "No");
     158    dprintf("\tTimer type: %s\n",
     159        timer->config & HPET_CONF_TIMER_TYPE ? "Periodic" : "OneShot");
     160    dprintf("\tInterrupt Type: %s\n",
     161        timer->config & HPET_CONF_TIMER_INT_TYPE ? "Level" : "Edge");
     162
     163    dprintf("\tconfigured IRQ: %lld\n",
     164        HPET_GET_CONF_TIMER_INT_ROUTE(timer));
     165
     166    if (timer->config & HPET_CONF_TIMER_FSB_ENABLE) {
     167        dprintf("\tfsb_route[0]: 0x%llx\n", timer->fsb_route[0]);
     168        dprintf("\tfsb_route[1]: 0x%llx\n", timer->fsb_route[1]);
     169    }
     170}
     171#endif
     172
     173
     174static void
     175hpet_init_timer(volatile struct hpet_timer *timer)
     176{
     177    sTimer = timer;
     178
     179    uint32 interrupt = 0;
     180
     181    sTimer->config |= (interrupt << HPET_CONF_TIMER_INT_ROUTE_SHIFT)
     182        & HPET_CONF_TIMER_INT_ROUTE_MASK;
     183
     184    // Non-periodic mode, edge triggered
     185    sTimer->config &= ~(HPET_CONF_TIMER_TYPE | HPET_CONF_TIMER_INT_TYPE);
     186
     187    sTimer->config &= ~HPET_CONF_TIMER_FSB_ENABLE;
     188    sTimer->config &= ~HPET_CONF_TIMER_32MODE;
     189
     190    // Enable timer
     191    sTimer->config |= HPET_CONF_TIMER_INT_ENABLE;
     192
     193#ifdef TRACE_HPET
     194    hpet_dump_timer(sTimer);
     195#endif
     196}
     197
     198
     199static status_t
     200hpet_test()
     201{
     202    uint64 initialValue = sHPETRegs->u0.counter64;
     203    spin(10);
     204    uint64 finalValue = sHPETRegs->u0.counter64;
     205
     206    if (initialValue == finalValue) {
     207        dprintf("hpet_test: counter does not increment\n");
     208        return B_ERROR;
     209    }
     210
     211    return B_OK;
     212}
     213
     214
     215static status_t
     216hpet_init(struct kernel_args *args)
     217{
     218    /* hpet_acpi_probe() through a similar "scan spots" table
     219       to that of smp.cpp.
     220       Seems to be the most elegant solution right now. */
     221    if (args->arch_args.hpet == NULL)
     222        return B_ERROR;
     223
     224    if (sHPETRegs == NULL) {
     225        sHPETRegs = (struct hpet_regs *)((void*)args->arch_args.hpet);
     226        if (vm_map_physical_memory(B_SYSTEM_TEAM, "hpet",
     227            (void **)&sHPETRegs, B_EXACT_ADDRESS, B_PAGE_SIZE,
     228            B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
     229            (phys_addr_t)args->arch_args.hpet_phys, true) < B_OK) {
     230            // Would it be better to panic here?
     231            dprintf("hpet_init: Failed to map memory for the HPET registers.");
     232            return B_ERROR;
     233        }
     234    }
     235
     236    sHPETPeriod = HPET_GET_PERIOD(sHPETRegs);
     237
     238    TRACE(("hpet_init: HPET is at %p.\n\tVendor ID: %llx, rev: %llx, period: %lld\n",
     239        sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs), HPET_GET_REVID(sHPETRegs),
     240        sHPETPeriod));
     241
     242    status_t status = hpet_set_enabled(false);
     243    if (status != B_OK)
     244        return status;
     245
     246    status = hpet_set_legacy(true);
     247    if (status != B_OK)
     248        return status;
     249
     250    uint32 numTimers = HPET_GET_NUM_TIMERS(sHPETRegs) + 1;
     251
     252    TRACE(("hpet_init: HPET supports %lu timers, and is %s bits wide.\n",
     253        numTimers, HPET_IS_64BIT(sHPETRegs) ? "64" : "32"));
     254
     255    TRACE(("hpet_init: configuration: 0x%llx, timer_interrupts: 0x%llx\n",
     256        sHPETRegs->config, sHPETRegs->interrupt_status));
     257
     258    if (numTimers < 3) {
     259        dprintf("hpet_init: HPET does not have at least 3 timers. Skipping.\n");
     260        return B_ERROR;
     261    }
     262
     263#ifdef TRACE_HPET
     264    for (uint32 c = 0; c < numTimers; c++)
     265        hpet_dump_timer(&sHPETRegs->timer[c]);
     266#endif
     267
     268    hpet_init_timer(&sHPETRegs->timer[0]);
     269
     270    status = hpet_set_enabled(true);
     271    if (status != B_OK)
     272        return status;
     273
     274#ifdef TEST_HPET
     275    status = hpet_test();
     276    if (status != B_OK)
     277        return status;
     278#endif
     279
     280    int32 configuredIRQ = HPET_GET_CONF_TIMER_INT_ROUTE(sTimer);
     281
     282    install_io_interrupt_handler(configuredIRQ, &hpet_timer_interrupt,
     283        NULL, B_NO_LOCK_VECTOR);
     284
     285    return status;
     286}
     287
  • src/system/kernel/arch/x86_64/timers/apic_timer.h

     
     1/*
     2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef _KERNEL_ARCH_x86_64_TIMERS_APIC_H
     6#define _KERNEL_ARCH_x86_64_TIMERS_APIC_H
     7
     8#include <SupportDefs.h>
     9
     10status_t apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu);
     11
     12#endif /* _KERNEL_ARCH_x86_64_TIMERS_APIC_H */
  • src/system/kernel/arch/x86_64/timers/pit.h

     
     1/*
     2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5#ifndef _KERNEL_ARCH_x86_64_TIMERS_PIT_H
     6#define _KERNEL_ARCH_x86_64_TIMERS_PIT_H
     7
     8#include <SupportDefs.h>
     9
     10/* ports */
     11#define PIT_CTRL    0x43
     12#define PIT_CNT0    0x40
     13#define PIT_CNT1    0x41
     14#define PIT_CNT2    0x42
     15
     16/* commands */
     17#define PIT_SELCH0  0x00
     18#define PIT_SELCH1  0x40
     19#define PIT_SELCH2  0x80
     20
     21#define PIT_RWLOW   0x10
     22#define PIT_RWHIGH  0x20
     23#define PIT_RWBOTH  0x30
     24
     25#define PIT_MD_INTON0   0x00
     26#define PIT_MD_ONESHOT  0x02
     27#define PIT_MD_RTGEN    0x04
     28#define PIT_MD_SQGEN    0x06
     29#define PIT_MD_SW_STRB  0x08
     30#define PIT_MD_HW_STRB  0x0A
     31
     32#define PIT_BCD     0x01
     33
     34#define PIT_LATCH   0x00
     35
     36#define PIT_READ    0xF0
     37#define PIT_CNT     0x20
     38#define PIT_STAT    0x10
     39
     40#define PIT_CLOCK_RATE  1193180
     41#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE)
     42
     43/* Method Prototypes */
     44static int pit_get_prio(void);
     45static status_t pit_set_hardware_timer(bigtime_t relativeTimeout);
     46static status_t pit_clear_hardware_timer(void);
     47static status_t pit_init(struct kernel_args *args);
     48
     49#endif /* _KERNEL_ARCH_x86_64_TIMERS_PIT_H */
  • src/system/kernel/arch/x86_64/timers/x86_64_apic.cpp

     
     1/*
     2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
     3 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     4 * Distributed under the terms of the MIT License.
     5 *
     6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     7 * Distributed under the terms of the NewOS License.
     8 */
     9
     10#include <timer.h>
     11#include <arch/x86_64/timer.h>
     12
     13#include <int.h>
     14#include <arch/x86_64/apic.h>
     15
     16#include <arch/cpu.h>
     17#include <arch/smp.h>
     18
     19#include "apic_timer.h"
     20
     21
     22/* Method Prototypes */
     23static int apic_timer_get_priority();
     24static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout);
     25static status_t apic_timer_clear_hardware_timer();
     26static status_t apic_timer_init(struct kernel_args *args);
     27
     28static uint32 sApicTicsPerSec = 0;
     29
     30struct timer_info gAPICTimer = {
     31    "APIC",
     32    &apic_timer_get_priority,
     33    &apic_timer_set_hardware_timer,
     34    &apic_timer_clear_hardware_timer,
     35    &apic_timer_init
     36};
     37
     38
     39static int
     40apic_timer_get_priority()
     41{
     42    return 3;
     43}
     44
     45
     46static int32
     47apic_timer_interrupt(void *data)
     48{
     49    return timer_interrupt();
     50}
     51
     52
     53#define MIN_TIMEOUT 1
     54
     55static status_t
     56apic_timer_set_hardware_timer(bigtime_t relativeTimeout)
     57{
     58    if (relativeTimeout < MIN_TIMEOUT)
     59        relativeTimeout = MIN_TIMEOUT;
     60
     61    // calculation should be ok, since it's going to be 64-bit
     62    uint32 ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000);
     63
     64    cpu_status state = disable_interrupts();
     65
     66    uint32 config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
     67    apic_write(APIC_LVT_TIMER, config);
     68
     69    apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
     70
     71    config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer
     72    apic_write(APIC_LVT_TIMER, config);
     73
     74    //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n",
     75    //  config, relativeTimeout, sApicTicsPerSec, ticks));
     76
     77    apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up
     78
     79    restore_interrupts(state);
     80
     81    return B_OK;
     82}
     83
     84
     85static status_t
     86apic_timer_clear_hardware_timer()
     87{
     88    cpu_status state = disable_interrupts();
     89
     90    uint32 config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED;
     91        // mask the timer
     92    apic_write(APIC_LVT_TIMER, config);
     93
     94    apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
     95
     96    restore_interrupts(state);
     97    return B_OK;
     98}
     99
     100
     101static status_t
     102apic_timer_init(struct kernel_args *args)
     103{
     104    if (!apic_available())
     105        return B_ERROR;
     106
     107    sApicTicsPerSec = args->arch_args.apic_time_cv_factor;
     108    install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE,
     109        &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
     110
     111    return B_OK;
     112}
     113
     114
     115status_t
     116apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu)
     117{
     118    /* setup timer */
     119    uint32 config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK;
     120    config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
     121    apic_write(APIC_LVT_TIMER, config);
     122
     123    apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock
     124
     125    config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0;
     126    config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
     127    apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
     128    return B_OK;
     129}
  • src/system/kernel/arch/x86_64/timers/x86_64_pit.cpp

     
     1/*
     2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
     3 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     4 * Distributed under the terms of the MIT License.
     5 *
     6 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     7 * Distributed under the terms of the NewOS License.
     8 */
     9
     10#include <timer.h>
     11#include <arch/x86_64/timer.h>
     12
     13#include <arch/int.h>
     14#include <arch/cpu.h>
     15
     16#include "pit.h"
     17
     18static bool sPITTimerInitialized = false;
     19
     20struct timer_info gPITTimer = {
     21    "PIT",
     22    &pit_get_prio,
     23    &pit_set_hardware_timer,
     24    &pit_clear_hardware_timer,
     25    &pit_init
     26};
     27
     28
     29static int
     30pit_get_prio(void)
     31{
     32    return 1;
     33}
     34
     35
     36static int32
     37pit_timer_interrupt(void *data)
     38{
     39    return timer_interrupt();
     40}
     41
     42
     43static status_t
     44pit_set_hardware_timer(bigtime_t relativeTimeout)
     45{
     46    uint16 nextEventClocks;
     47
     48    if (relativeTimeout <= 0)
     49        nextEventClocks = 2;
     50    else if (relativeTimeout < PIT_MAX_TIMER_INTERVAL)
     51        nextEventClocks = relativeTimeout * PIT_CLOCK_RATE / 1000000;
     52    else
     53        nextEventClocks = 0xffff;
     54
     55    out8(PIT_SELCH0 | PIT_RWBOTH | PIT_MD_INTON0, PIT_CTRL);
     56    out8(nextEventClocks & 0xff, PIT_CNT0);
     57    out8((nextEventClocks >> 8) & 0xff, PIT_CNT0);
     58
     59    arch_int_enable_io_interrupt(0);
     60    return B_OK;
     61}
     62
     63
     64static status_t
     65pit_clear_hardware_timer(void)
     66{
     67    arch_int_disable_io_interrupt(0);
     68    return B_OK;
     69}
     70
     71
     72static status_t
     73pit_init(struct kernel_args *args)
     74{
     75    if (sPITTimerInitialized) {
     76        return B_OK;
     77    }
     78   
     79    install_io_interrupt_handler(0, &pit_timer_interrupt, NULL, 0);
     80    pit_clear_hardware_timer();
     81
     82    sPITTimerInitialized = true;
     83
     84    return B_OK;
     85}
  • src/system/kernel/arch/x86_64/arch_debug.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
     5 * Distributed under the terms of the MIT License.
     6 *
     7 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     8 * Distributed under the terms of the NewOS License.
     9 */
     10
     11#include <KernelExport.h>
     12
     13#include <arch/debug.h>
     14
     15#include <stdio.h>
     16#include <stdlib.h>
     17
     18#include <TypeConstants.h>
     19
     20#include <cpu.h>
     21#include <debug.h>
     22#include <debug_heap.h>
     23#include <elf.h>
     24#include <kernel.h>
     25#include <kimage.h>
     26#include <thread.h>
     27#include <vm/vm.h>
     28#include <vm/vm_types.h>
     29#include <vm/VMAddressSpace.h>
     30#include <vm/VMArea.h>
     31
     32#include <arch_cpu.h>
     33
     34
     35struct stack_frame {
     36    struct stack_frame  *previous;
     37    addr_t              return_address;
     38};
     39
     40#define NUM_PREVIOUS_LOCATIONS 32
     41
     42
     43static status_t
     44lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress,
     45    const char **_symbolName, const char **_imageName, bool *_exactMatch)
     46{
     47    status_t status = B_ENTRY_NOT_FOUND;
     48
     49    if (IS_KERNEL_ADDRESS(address)) {
     50        // a kernel symbol
     51        status = elf_debug_lookup_symbol_address(address, _baseAddress,
     52            _symbolName, _imageName, _exactMatch);
     53    } else if (thread != NULL && thread->team != NULL) {
     54        // try a lookup using the userland runtime loader structures
     55        status = elf_debug_lookup_user_symbol_address(thread->team, address,
     56            _baseAddress, _symbolName, _imageName, _exactMatch);
     57
     58        if (status != B_OK) {
     59            // try to locate the image in the images loaded into user space
     60            status = image_debug_lookup_user_symbol_address(thread->team,
     61                address, _baseAddress, _symbolName, _imageName, _exactMatch);
     62        }
     63    }
     64
     65    return status;
     66}
     67
     68
     69static bool
     70is_double_fault_stack_address(int32 cpu, addr_t address)
     71{
     72    size_t size;
     73    addr_t bottom = (addr_t)x86_64_get_double_fault_stack(cpu, &size);
     74    return address >= bottom && address < bottom + size;
     75}
     76
     77
     78static bool
     79is_kernel_stack_address(struct thread* thread, addr_t address)
     80{
     81    // We don't have a thread pointer in the early boot process, but then we are
     82    // on the kernel stack for sure.
     83    if (thread == NULL)
     84        return IS_KERNEL_ADDRESS(address);
     85
     86    // Also in the early boot process we might have a thread structure, but it
     87    // might not have its kernel stack attributes set yet.
     88    if (thread->kernel_stack_top == 0)
     89        return IS_KERNEL_ADDRESS(address);
     90
     91    return (address >= thread->kernel_stack_base
     92            && address < thread->kernel_stack_top)
     93        || (thread->cpu != NULL
     94            && is_double_fault_stack_address(thread->cpu->cpu_num, address));
     95}
     96
     97
     98static bool
     99is_iframe(struct thread* thread, addr_t frame)
     100{
     101    if (!is_kernel_stack_address(thread, frame))
     102        return false;
     103
     104    addr_t previousFrame = *(addr_t*)frame;
     105    return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0);
     106}
     107
     108
     109static struct iframe *
     110find_previous_iframe(struct thread *thread, addr_t frame)
     111{
     112    // iterate backwards through the stack frames, until we hit an iframe
     113    while (is_kernel_stack_address(thread, frame)) {
     114        if (is_iframe(thread, frame))
     115            return (struct iframe*)frame;
     116
     117        frame = *(addr_t*)frame;
     118    }
     119
     120    return NULL;
     121}
     122
     123static struct iframe*
     124get_previous_iframe(struct thread* thread, struct iframe* frame)
     125{
     126    if (frame == NULL)
     127        return NULL;
     128
     129    return find_previous_iframe(thread, frame->rbp);
     130}
     131
     132static struct iframe*
     133get_current_iframe(struct thread* thread)
     134{
     135    if (thread == thread_get_current_thread())
     136        return x86_64_get_current_iframe();
     137
     138    addr_t rbp = thread->arch_info.current_stack.rsp[2];
     139        // NOTE: This doesn't work, if the thread is running (on another CPU).
     140    return find_previous_iframe(thread, rbp);
     141}
     142
     143uint64*
     144find_debug_variable(const char* variableName, bool& settable)
     145{
     146    struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
     147    if (frame == NULL)
     148        return NULL;
     149
     150    settable = false;
     151
     152    if (strcmp(variableName, "gs") == 0) {
     153        return &frame->gs;
     154    } else if (strcmp(variableName, "fs") == 0) {
     155        return &frame->fs;
     156    } else if (strcmp(variableName, "es") == 0) {
     157        return &frame->es;
     158    } else if (strcmp(variableName, "ds") == 0) {
     159        return &frame->ds;
     160    } else if (strcmp(variableName, "cs") == 0) {
     161        return &frame->cs;
     162    } else if (strcmp(variableName, "rdi") == 0) {
     163        settable = true;
     164        return &frame->rdi;
     165    } else if (strcmp(variableName, "rsi") == 0) {
     166        settable = true;
     167        return &frame->rsi;
     168    } else if (strcmp(variableName, "rbp") == 0) {
     169        settable = true;
     170        return &frame->rbp;
     171    } else if (strcmp(variableName, "rsp") == 0) {
     172        settable = true;
     173        return &frame->rsp;
     174    } else if (strcmp(variableName, "rbx") == 0) {
     175        settable = true;
     176        return &frame->rbx;
     177    } else if (strcmp(variableName, "rdx") == 0) {
     178        settable = true;
     179        return &frame->rdx;
     180    } else if (strcmp(variableName, "rcx") == 0) {
     181        settable = true;
     182        return &frame->rcx;
     183    } else if (strcmp(variableName, "rax") == 0) {
     184        settable = true;
     185        return &frame->rax;
     186    } else if (strcmp(variableName, "r8") == 0) {
     187        settable = true;
     188        return &frame->r8;
     189    } else if (strcmp(variableName, "r9") == 0) {
     190        settable = true;
     191        return &frame->r9;
     192    } else if (strcmp(variableName, "r10") == 0) {
     193        settable = true;
     194        return &frame->r10;
     195    } else if (strcmp(variableName, "r11") == 0) {
     196        settable = true;
     197        return &frame->r11;
     198    } else if (strcmp(variableName, "r12") == 0) {
     199        settable = true;
     200        return &frame->r12;
     201    } else if (strcmp(variableName, "r13") == 0) {
     202        settable = true;
     203        return &frame->r13;
     204    } else if (strcmp(variableName, "r14") == 0) {
     205        settable = true;
     206        return &frame->r14;
     207    } else if (strcmp(variableName, "r15") == 0) {
     208        settable = true;
     209        return &frame->r15;
     210    } else if (strcmp(variableName, "orig_rax") == 0) {
     211        settable = true;
     212        return &frame->orig_rax;
     213    } else if (strcmp(variableName, "orig_rdx") == 0) {
     214        settable = true;
     215        return &frame->orig_rdx;
     216    } else if (strcmp(variableName, "rip") == 0) {
     217        settable = true;
     218        return &frame->rip;
     219    } else if (strcmp(variableName, "rflags") == 0) {
     220        settable = true;
     221        return (uint64*)(&frame->flags);
     222    }
     223
     224    if (IFRAME_IS_USER(frame)) {
     225        if (strcmp(variableName, "user_rsp") == 0) {
     226            settable = true;
     227            return &frame->user_rsp;
     228        } else if (strcmp(variableName, "user_ss") == 0) {
     229            return &frame->user_ss;
     230        }
     231    }
     232
     233    return NULL;
     234}
     235
     236
     237static void
     238print_iframe(struct iframe *frame)
     239{
     240    bool isUser = IFRAME_IS_USER(frame);
     241    kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
     242        isUser ? (uint64*)(frame + 1) : &frame->user_rsp);
     243
     244    kprintf(" rax 0x%-9llx    rbx 0x%-9llx     rcx 0x%-9llx  rdx 0x%llx\n",
     245        frame->rax, frame->rbx, frame->rcx, frame->rdx);
     246    kprintf(" rsi 0x%-9llx    rdi 0x%-9llx     rbp 0x%-9llx  rsp 0x%llx\n",
     247        frame->rsi, frame->rdi, frame->rbp, frame->rsp);
     248    kprintf(" rip 0x%-9llx eflags 0x%-9lx", frame->rip, frame->flags);
     249    if (isUser) {
     250        // from user space
     251        kprintf("user rsp 0x%llx", frame->user_rsp);
     252    }
     253    kprintf("\n");
     254    kprintf(" vector: 0x%llx, error code: 0x%llx\n", frame->vector,
     255        frame->error_code);
     256}
     257
     258
     259static bool
     260setup_for_thread(char *arg, struct thread **_thread, uint64 *_rbp,
     261    uint64 *_oldPageDirectory)
     262{
     263    struct thread *thread = NULL;
     264
     265    if (arg != NULL) {
     266        thread_id id = strtoul(arg, NULL, 0);
     267        thread = thread_get_thread_struct_locked(id);
     268        if (thread == NULL) {
     269            kprintf("could not find thread %ld\n", id);
     270            return false;
     271        }
     272
     273        if (id != thread_get_current_thread_id()) {
     274            // switch to the page directory of the new thread to be
     275            // able to follow the stack trace into userland
     276            uint32 newPageDirectory = x86_64_next_page_directory(
     277                thread_get_current_thread(), thread);
     278
     279            if (newPageDirectory != 0) {
     280                read_cr3(*_oldPageDirectory);
     281                write_cr3(newPageDirectory);
     282            }
     283
     284            if (thread->state == B_THREAD_RUNNING) {
     285                // The thread is currently running on another CPU.
     286                if (thread->cpu == NULL)
     287                    return false;
     288                arch_debug_registers* registers = debug_get_debug_registers(
     289                    thread->cpu->cpu_num);
     290                if (registers == NULL)
     291                    return false;
     292                *_rbp = registers->rbp;
     293            } else {
     294                // read %ebp from the thread's stack stored by a pushad
     295                *_rbp = thread->arch_info.current_stack.rsp[2];
     296            }
     297        } else
     298            thread = NULL;
     299    }
     300
     301    if (thread == NULL) {
     302        // if we don't have a thread yet, we want the current one
     303        // (ebp has been set by the caller for this case already)
     304        thread = thread_get_current_thread();
     305    }
     306
     307    *_thread = thread;
     308    return true;
     309}
     310
     311
     312void
     313arch_debug_save_registers(struct arch_debug_registers* registers)
     314{
     315    // get the caller's frame pointer
     316    stack_frame* frame = (stack_frame*)x86_64_read_rbp();
     317    registers->rbp = (addr_t)frame->previous;
     318}
     319
     320
     321static bool
     322is_calling(struct thread *thread, addr_t rip, const char *pattern,
     323    addr_t start, addr_t end)
     324{
     325    if (pattern == NULL)
     326        return rip >= start && rip < end;
     327
     328    if (!IS_KERNEL_ADDRESS(rip))
     329        return false;
     330
     331    const char *symbol;
     332    if (lookup_symbol(thread, rip, NULL, &symbol, NULL, NULL) != B_OK)
     333        return false;
     334
     335    return strstr(symbol, pattern);
     336}
     337
     338
     339static status_t
     340get_next_frame_no_debugger(addr_t rbp, addr_t *_next, addr_t *_rip)
     341{
     342    // TODO: Do this more efficiently in assembly.
     343    stack_frame frame;
     344    if (user_memcpy(&frame, (void*)rbp, sizeof(frame)) != B_OK)
     345        return B_BAD_ADDRESS;
     346
     347    *_rip = frame.return_address;
     348    *_next = (addr_t)frame.previous;
     349
     350    return B_OK;
     351}
     352
     353
     354bool
     355arch_debug_contains_call(struct thread *thread, const char *symbol,
     356    addr_t start, addr_t end)
     357{
     358    DebuggedThreadSetter threadSetter(thread);
     359
     360    addr_t rbp;
     361    if (thread == thread_get_current_thread())
     362        rbp = x86_64_read_rbp();
     363    else {
     364        if (thread->state == B_THREAD_RUNNING) {
     365            // The thread is currently running on another CPU.
     366            if (thread->cpu == NULL)
     367                return false;
     368            arch_debug_registers* registers = debug_get_debug_registers(
     369                thread->cpu->cpu_num);
     370            if (registers == NULL)
     371                return false;
     372            rbp = registers->rbp;
     373        } else {
     374            // thread not running
     375            rbp = thread->arch_info.current_stack.rsp[2];
     376        }
     377    }
     378
     379    for (;;) {
     380        if (!is_kernel_stack_address(thread, rbp))
     381            break;
     382
     383        if (is_iframe(thread, rbp)) {
     384            struct iframe *frame = (struct iframe *)rbp;
     385
     386            if (is_calling(thread, frame->rip, symbol, start, end))
     387                return true;
     388
     389            rbp = frame->rbp;
     390        } else {
     391            addr_t rip, nextRbp;
     392
     393            if (get_next_frame_no_debugger(rbp, &nextRbp, &rip) != B_OK
     394                || rip == 0 || rbp == 0)
     395                break;
     396
     397            if (is_calling(thread, rip, symbol, start, end))
     398                return true;
     399
     400            rbp = nextRbp;
     401        }
     402
     403        if (rbp == 0)
     404            break;
     405    }
     406
     407    return false;
     408}
     409
     410
     411void *
     412arch_debug_get_caller(void)
     413{
     414    struct stack_frame *frame = (struct stack_frame *)x86_64_read_rbp();
     415    return (void *)frame->previous->return_address;
     416}
     417
     418
     419void*
     420arch_debug_get_interrupt_pc(bool* _isSyscall)
     421{
     422    struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
     423    if (frame == NULL)
     424        return NULL;
     425
     426    if (_isSyscall != NULL)
     427        *_isSyscall = frame->vector == 99;
     428
     429    return (void*)(addr_t)frame->rip;
     430}
     431
     432
     433bool
     434arch_is_debug_variable_defined(const char* variableName)
     435{
     436    bool settable;
     437    return find_debug_variable(variableName, settable);
     438}
     439
     440
     441status_t
     442arch_set_debug_variable(const char* variableName, uint64 value)
     443{
     444    bool settable;
     445    uint64* variable = find_debug_variable(variableName, settable);
     446    if (variable == NULL)
     447        return B_ENTRY_NOT_FOUND;
     448
     449    if (!settable)
     450        return B_NOT_ALLOWED;
     451
     452    *variable = (uint64)value;
     453    return B_OK;
     454}
     455
     456
     457status_t
     458arch_get_debug_variable(const char* variableName, uint64* value)
     459{
     460    bool settable;
     461    uint64* variable = find_debug_variable(variableName, settable);
     462    if (variable == NULL)
     463        return B_ENTRY_NOT_FOUND;
     464
     465    *value = *variable;
     466    return B_OK;
     467}
     468
     469/*
     470void
     471arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
     472    void (*function)(void*), void* parameter)
     473
     474    moved to arch_x86_64.S
     475*/
     476
     477
     478void
     479arch_debug_unset_current_thread(void)
     480{
     481    write_dr3(NULL);
     482}
     483
     484
     485static void
     486set_debug_argument_variable(int32 index, uint64 value)
     487{
     488    char name[8];
     489    snprintf(name, sizeof(name), "_arg%ld", index);
     490    set_debug_variable(name, value);
     491}
     492
     493
     494template<typename Type>
     495static Type
     496read_function_argument_value(void* argument, bool& _valueKnown)
     497{
     498    Type value;
     499    if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) {
     500        _valueKnown = true;
     501        return value;
     502    }
     503
     504    _valueKnown = false;
     505    return 0;
     506}
     507
     508
     509static status_t
     510print_demangled_call(const char* image, const char* symbol, addr_t args,
     511    bool noObjectMethod, bool addDebugVariables)
     512{
     513    static const size_t kBufferSize = 256;
     514    char* buffer = (char*)debug_malloc(kBufferSize);
     515    if (buffer == NULL)
     516        return B_NO_MEMORY;
     517
     518    bool isObjectMethod;
     519    const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
     520        &isObjectMethod);
     521    if (name == NULL) {
     522        debug_free(buffer);
     523        return B_ERROR;
     524    }
     525
     526    uint64* arg = (uint64*)args;
     527
     528    if (noObjectMethod)
     529        isObjectMethod = false;
     530    if (isObjectMethod) {
     531        const char* lastName = strrchr(name, ':') - 1;
     532        int namespaceLength = lastName - name;
     533
     534        uint32 argValue = 0;
     535        if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) {
     536            kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image,
     537                namespaceLength, name, argValue, lastName);
     538        } else
     539            kprintf("<%s> %.*s<???>%s", image, namespaceLength, name, lastName);
     540
     541        if (addDebugVariables)
     542            set_debug_variable("_this", argValue);
     543        arg++;
     544    } else
     545        kprintf("<%s> %s", image, name);
     546
     547    kprintf("(");
     548
     549    size_t length;
     550    int32 type, i = 0;
     551    uint32 cookie = 0;
     552    while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
     553            kBufferSize, &type, &length) == B_OK) {
     554        if (i++ > 0)
     555            kprintf(", ");
     556
     557        // retrieve value and type identifier
     558
     559        uint64 value;
     560        bool valueKnown = false;
     561
     562        switch (type) {
     563            case B_INT64_TYPE:
     564                value = read_function_argument_value<int64>(arg, valueKnown);
     565                if (valueKnown)
     566                    kprintf("int64: \33[34m%Ld\33[0m", value);
     567                break;
     568            case B_INT32_TYPE:
     569                value = read_function_argument_value<int32>(arg, valueKnown);
     570                if (valueKnown)
     571                    kprintf("int32: \33[34m%ld\33[0m", (int32)value);
     572                break;
     573            case B_INT16_TYPE:
     574                value = read_function_argument_value<int16>(arg, valueKnown);
     575                if (valueKnown)
     576                    kprintf("int16: \33[34m%d\33[0m", (int16)value);
     577                break;
     578            case B_INT8_TYPE:
     579                value = read_function_argument_value<int8>(arg, valueKnown);
     580                if (valueKnown)
     581                    kprintf("int8: \33[34m%d\33[0m", (int8)value);
     582                break;
     583            case B_UINT64_TYPE:
     584                value = read_function_argument_value<uint64>(arg, valueKnown);
     585                if (valueKnown) {
     586                    kprintf("uint64: \33[34m%#Lx\33[0m", value);
     587                    if (value < 0x100000)
     588                        kprintf(" (\33[34m%Lu\33[0m)", value);
     589                }
     590                break;
     591            case B_UINT32_TYPE:
     592                value = read_function_argument_value<uint32>(arg, valueKnown);
     593                if (valueKnown) {
     594                    kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value);
     595                    if (value < 0x100000)
     596                        kprintf(" (\33[34m%lu\33[0m)", (uint32)value);
     597                }
     598                break;
     599            case B_UINT16_TYPE:
     600                value = read_function_argument_value<uint16>(arg, valueKnown);
     601                if (valueKnown) {
     602                    kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
     603                        (uint16)value, (uint16)value);
     604                }
     605                break;
     606            case B_UINT8_TYPE:
     607                value = read_function_argument_value<uint8>(arg, valueKnown);
     608                if (valueKnown) {
     609                    kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
     610                        (uint8)value, (uint8)value);
     611                }
     612                break;
     613            case B_BOOL_TYPE:
     614                value = read_function_argument_value<uint8>(arg, valueKnown);
     615                if (valueKnown)
     616                    kprintf("\33[34m%s\33[0m", value ? "true" : "false");
     617                break;
     618            default:
     619                if (buffer[0])
     620                    kprintf("%s: ", buffer);
     621
     622                if (length == 4) {
     623                    value = read_function_argument_value<uint32>(arg,
     624                        valueKnown);
     625                    if (valueKnown) {
     626                        if (value == 0
     627                            && (type == B_POINTER_TYPE || type == B_REF_TYPE))
     628                            kprintf("NULL");
     629                        else
     630                            kprintf("\33[34m%#lx\33[0m", (uint32)value);
     631                    }
     632                    break;
     633                }
     634
     635
     636                if (length == 8) {
     637                    value = read_function_argument_value<uint64>(arg,
     638                        valueKnown);
     639                } else
     640                    value = (uint64)arg;
     641
     642                if (valueKnown)
     643                    kprintf("\33[34m%#Lx\33[0m", value);
     644                break;
     645        }
     646
     647        if (!valueKnown)
     648            kprintf("???");
     649
     650        if (valueKnown && type == B_STRING_TYPE) {
     651            if (value == 0)
     652                kprintf(" \33[31m\"<NULL>\"\33[0m");
     653            else if (debug_strlcpy(B_CURRENT_TEAM, buffer, (char*)value,
     654                    kBufferSize) < B_OK) {
     655                kprintf(" \33[31m\"<???>\"\33[0m");
     656            } else
     657                kprintf(" \33[36m\"%s\"\33[0m", buffer);
     658        }
     659
     660        if (addDebugVariables)
     661            set_debug_argument_variable(i, value);
     662        arg = (uint64*)((uint8*)arg + length);
     663    }
     664
     665    debug_free(buffer);
     666
     667    kprintf(")");
     668    return B_OK;
     669}
     670
     671
     672static void
     673print_call(struct thread *thread, addr_t rip, addr_t rbp, addr_t nextRbp,
     674    int32 argCount)
     675{
     676    const char *symbol, *image;
     677    addr_t baseAddress;
     678    bool exactMatch;
     679    status_t status;
     680    bool demangled = false;
     681    int64 *arg = (int64 *)(nextRbp + 8);
     682
     683    status = lookup_symbol(thread, rip, &baseAddress, &symbol, &image,
     684        &exactMatch);
     685
     686    kprintf("%08lx %08lx   ", rbp, rip);
     687
     688    if (status == B_OK) {
     689        if (symbol != NULL) {
     690            if (exactMatch && (argCount == 0 || argCount == -1)) {
     691                status = print_demangled_call(image, symbol, (addr_t)arg,
     692                    argCount == -1, true);
     693                if (status == B_OK)
     694                    demangled = true;
     695            }
     696            if (!demangled) {
     697                kprintf("<%s>:%s%s", image, symbol,
     698                    exactMatch ? "" : " (nearest)");
     699            }
     700        } else {
     701            kprintf("<%s@%p>:unknown + 0x%04lx", image,
     702                (void *)baseAddress, rip - baseAddress);
     703        }
     704    } else {
     705        VMArea *area = NULL;
     706        if (thread->team->address_space != NULL)
     707            area = thread->team->address_space->LookupArea(rip);
     708        if (area != NULL) {
     709            kprintf("%ld:%s@%p + %#lx", area->id, area->name,
     710                (void *)area->Base(), rip - area->Base());
     711        }
     712    }
     713
     714    if (!demangled) {
     715        kprintf("(");
     716
     717        for (int32 i = 0; i < argCount; i++) {
     718            if (i > 0)
     719                kprintf(", ");
     720            kprintf("%#llx", *arg);
     721            if (*arg > -0x10000 && *arg < 0x10000)
     722                kprintf(" (%lld)", *arg);
     723
     724            set_debug_argument_variable(i + 1, *(uint32 *)arg);
     725            arg++;
     726        }
     727
     728        kprintf(")\n");
     729    } else
     730        kprintf("\n");
     731
     732    set_debug_variable("_frame", nextRbp);
     733}
     734
     735
     736static int
     737dump_iframes(int argc, char **argv)
     738{
     739    static const char* usage = "usage: %s [ <thread id> ]\n"
     740        "Prints the iframe stack for the current, respectively the specified\n"
     741        "thread.\n"
     742        "  <thread id>  -  The ID of the thread for which to print the iframe\n"
     743        "                  stack.\n";
     744    if (argc == 2 && strcmp(argv[1], "--help") == 0) {
     745        kprintf(usage, argv[0]);
     746        return 0;
     747    }
     748
     749    struct thread *thread = NULL;
     750
     751    if (argc < 2) {
     752        thread = thread_get_current_thread();
     753    } else if (argc == 2) {
     754        thread_id id = strtoul(argv[1], NULL, 0);
     755        thread = thread_get_thread_struct_locked(id);
     756        if (thread == NULL) {
     757            kprintf("could not find thread %ld\n", id);
     758            return 0;
     759        }
     760    } else if (argc > 2) {
     761        kprintf(usage, argv[0]);
     762        return 0;
     763    }
     764
     765    if (thread != NULL)
     766        kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name);
     767
     768    DebuggedThreadSetter threadSetter(thread);
     769
     770    struct iframe* frame = find_previous_iframe(thread, x86_64_read_rbp());
     771    while (frame != NULL) {
     772        print_iframe(frame);
     773        frame = get_previous_iframe(thread, frame);
     774    }
     775
     776    return 0;
     777}
     778
     779
     780static status_t
     781get_next_frame_debugger(addr_t rbp, addr_t *_next, addr_t *_rip)
     782{
     783    stack_frame frame;
     784    if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)rbp, sizeof(frame)) != B_OK)
     785        return B_BAD_ADDRESS;
     786
     787    *_rip = frame.return_address;
     788    *_next = (addr_t)frame.previous;
     789
     790    return B_OK;
     791}
     792
     793
     794static int
     795show_call(int argc, char **argv)
     796{
     797    static const char* usage
     798        = "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n"
     799        "Prints a function call with parameters of the current, respectively\n"
     800        "the specified thread.\n"
     801        "  <thread id>   -  The ID of the thread for which to print the call.\n"
     802        "  <call index>  -  The index of the call in the stack trace.\n"
     803        "  <arg count>   -  The number of call arguments to print (use 'c' to\n"
     804        "                   force the C++ demangler to use class methods,\n"
     805        "                   use 'd' to disable demangling).\n";
     806    if (argc == 2 && strcmp(argv[1], "--help") == 0) {
     807        kprintf(usage, argv[0]);
     808        return 0;
     809    }
     810
     811    struct thread *thread = NULL;
     812    uint64 oldPageDirectory = 0;
     813    uint64 rbp = x86_64_read_rbp();
     814    int32 argCount = 0;
     815
     816    if (argc >= 2 && argv[argc - 1][0] == '-') {
     817        if (argv[argc - 1][1] == 'c')
     818            argCount = -1;
     819        else if (argv[argc - 1][1] == 'd')
     820            argCount = -2;
     821        else
     822            argCount = strtoul(argv[argc - 1] + 1, NULL, 0);
     823
     824        if (argCount < -2 || argCount > 16) {
     825            kprintf("Invalid argument count \"%ld\".\n", argCount);
     826            return 0;
     827        }
     828        argc--;
     829    }
     830
     831    if (argc < 2 || argc > 3) {
     832        kprintf(usage, argv[0]);
     833        return 0;
     834    }
     835
     836    if (!setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &rbp,
     837            &oldPageDirectory))
     838        return 0;
     839
     840    DebuggedThreadSetter threadSetter(thread);
     841
     842    int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0);
     843
     844    if (thread != NULL)
     845        kprintf("thread %ld, %s\n", thread->id, thread->name);
     846
     847    bool onKernelStack = true;
     848
     849    for (int32 index = 0; index <= callIndex; index++) {
     850        onKernelStack = onKernelStack
     851            && is_kernel_stack_address(thread, rbp);
     852
     853        if (onKernelStack && is_iframe(thread, rbp)) {
     854            struct iframe *frame = (struct iframe *)rbp;
     855
     856            if (index == callIndex)
     857                print_call(thread, frame->rip, rbp, frame->rbp, argCount);
     858
     859            rbp = frame->rbp;
     860        } else {
     861            addr_t rip, nextRbp;
     862
     863            if (get_next_frame_debugger(rbp, &nextRbp, &rip) != B_OK) {
     864                kprintf("%08llx -- read fault\n", rbp);
     865                break;
     866            }
     867
     868            if (rip == 0 || rbp == 0)
     869                break;
     870
     871            if (index == callIndex)
     872                print_call(thread, rip, rbp, nextRbp, argCount);
     873
     874            rbp = nextRbp;
     875        }
     876
     877        if (rbp == 0)
     878            break;
     879    }
     880
     881    if (oldPageDirectory != 0) {
     882        // switch back to the previous page directory to not cause any troubles
     883        write_cr3(oldPageDirectory);
     884    }
     885
     886    return 0;
     887}
     888
     889
     890static void
     891print_stack_frame(struct thread *thread, addr_t rip, addr_t rbp, addr_t nextRbp,
     892    int32 callIndex, bool demangle)
     893{
     894    const char *symbol, *image;
     895    addr_t baseAddress;
     896    bool exactMatch;
     897    status_t status;
     898    addr_t diff;
     899
     900    diff = nextRbp - rbp;
     901
     902    // kernel space/user space switch
     903    if (diff & 0x80000000)
     904        diff = 0;
     905
     906    status = lookup_symbol(thread, rip, &baseAddress, &symbol, &image,
     907        &exactMatch);
     908
     909    kprintf("%2ld %08lx (+%4ld) %08lx   ", callIndex, rbp, diff, rip);
     910
     911    if (status == B_OK) {
     912        if (exactMatch && demangle) {
     913            status = print_demangled_call(image, symbol, nextRbp + 8, false,
     914                false);
     915        }
     916
     917        if (!exactMatch || !demangle || status != B_OK) {
     918            if (symbol != NULL) {
     919                kprintf("<%s>:%s%s", image, symbol,
     920                    exactMatch ? "" : " (nearest)");
     921            } else
     922                kprintf("<%s@%p>:unknown", image, (void *)baseAddress);
     923        }
     924
     925        kprintf(" + 0x%04lx\n", rip - baseAddress);
     926    } else {
     927        VMArea *area = NULL;
     928        if (thread != NULL && thread->team != NULL
     929            && thread->team->address_space != NULL) {
     930            area = thread->team->address_space->LookupArea(rip);
     931        }
     932        if (area != NULL) {
     933            kprintf("%ld:%s@%p + %#lx\n", area->id, area->name,
     934                (void*)area->Base(), rip - area->Base());
     935        } else
     936            kprintf("\n");
     937    }
     938}
     939
     940
     941static bool
     942already_visited(uint64 *visited, int32 *_last, int32 *_num, uint64 rbp)
     943{
     944    int32 last = *_last;
     945    int32 num = *_num;
     946    int32 i;
     947
     948    for (i = 0; i < num; i++) {
     949        if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == rbp)
     950            return true;
     951    }
     952
     953    *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
     954    visited[last] = rbp;
     955
     956    if (num < NUM_PREVIOUS_LOCATIONS)
     957        *_num = num + 1;
     958
     959    return false;
     960}
     961
     962
     963static int
     964stack_trace(int argc, char **argv)
     965{
     966    static const char* usage = "usage: %s [-d] [ <thread id> ]\n"
     967        "Prints a stack trace for the current, respectively the specified\n"
     968        "thread.\n"
     969        "  -d           -  Disables the demangling of the symbols.\n"
     970        "  <thread id>  -  The ID of the thread for which to print the stack\n"
     971        "                  trace.\n";
     972    bool demangle = true;
     973    int32 threadIndex = 1;
     974    if (argc > 1 && !strcmp(argv[1], "-d")) {
     975        demangle = false;
     976        threadIndex++;
     977    }
     978
     979    if (argc > threadIndex + 1
     980        || (argc == 2 && strcmp(argv[1], "--help") == 0)) {
     981        kprintf(usage, argv[0]);
     982        return 0;
     983    }
     984
     985    uint64 previousLocations[NUM_PREVIOUS_LOCATIONS];
     986    struct thread *thread = NULL;
     987    uint64 oldPageDirectory = 0;
     988    uint64 rbp = x86_64_read_rbp();
     989    int32 num = 0, last = 0;
     990
     991    if (!setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL,
     992            &thread, &rbp, &oldPageDirectory))
     993        return 0;
     994
     995    DebuggedThreadSetter threadSetter(thread);
     996
     997    if (thread != NULL) {
     998        kprintf("stack trace for thread %ld \"%s\"\n", thread->id,
     999            thread->name);
     1000
     1001        kprintf("    kernel stack: %p to %p\n",
     1002            (void *)thread->kernel_stack_base,
     1003            (void *)(thread->kernel_stack_top));
     1004        if (thread->user_stack_base != 0) {
     1005            kprintf("      user stack: %p to %p\n",
     1006                (void *)thread->user_stack_base,
     1007                (void *)(thread->user_stack_base + thread->user_stack_size));
     1008        }
     1009    }
     1010
     1011    kprintf("frame               caller     <image>:function + offset\n");
     1012
     1013    bool onKernelStack = true;
     1014
     1015    for (int32 callIndex = 0;; callIndex++) {
     1016        onKernelStack = onKernelStack
     1017            && is_kernel_stack_address(thread, rbp);
     1018
     1019        if (onKernelStack && is_iframe(thread, rbp)) {
     1020            struct iframe *frame = (struct iframe *)rbp;
     1021
     1022            print_iframe(frame);
     1023            print_stack_frame(thread, frame->rip, rbp, frame->rbp, callIndex,
     1024                demangle);
     1025
     1026            rbp = frame->rbp;
     1027        } else {
     1028            addr_t rip, nextRbp;
     1029
     1030            if (get_next_frame_debugger(rbp, &nextRbp, &rip) != B_OK) {
     1031                kprintf("%08llx -- read fault\n", rbp);
     1032                break;
     1033            }
     1034
     1035            if (rip == 0 || rbp == 0)
     1036                break;
     1037
     1038            print_stack_frame(thread, rip, rbp, nextRbp, callIndex, demangle);
     1039            rbp = nextRbp;
     1040        }
     1041
     1042        if (already_visited(previousLocations, &last, &num, rbp)) {
     1043            kprintf("circular stack frame: %p!\n", (void *)rbp);
     1044            break;
     1045        }
     1046        if (rbp == 0)
     1047            break;
     1048    }
     1049
     1050    if (oldPageDirectory != 0) {
     1051        // switch back to the previous page directory to no cause any troubles
     1052        write_cr3(oldPageDirectory);
     1053    }
     1054
     1055    return 0;
     1056}
     1057
     1058
     1059void
     1060arch_debug_stack_trace(void)
     1061{
     1062    stack_trace(0, NULL);
     1063}
     1064
     1065
     1066static int
     1067cmd_in_context(int argc, char** argv)
     1068{
     1069    if (argc != 2) {
     1070        print_debugger_command_usage(argv[0]);
     1071        return 0;
     1072    }
     1073
     1074    // get the thread ID
     1075    const char* commandLine = argv[1];
     1076    char threadIDString[16];
     1077    if (parse_next_debug_command_argument(&commandLine, threadIDString,
     1078            sizeof(threadIDString)) != B_OK) {
     1079        kprintf("Failed to parse thread ID.\n");
     1080        return 0;
     1081    }
     1082
     1083    if (commandLine == NULL) {
     1084        print_debugger_command_usage(argv[0]);
     1085        return 0;
     1086    }
     1087
     1088    uint64 threadID;
     1089    if (!evaluate_debug_expression(threadIDString, &threadID, false))
     1090        return 0;
     1091
     1092    // get the thread
     1093    struct thread* thread = thread_get_thread_struct_locked(threadID);
     1094    if (thread == NULL) {
     1095        kprintf("Could not find thread with ID \"%s\".\n", threadIDString);
     1096        return 0;
     1097    }
     1098
     1099    // switch the page directory, if necessary
     1100    uint32 oldPageDirectory = 0;
     1101    if (thread != thread_get_current_thread()) {
     1102        uint32 newPageDirectory = x86_64_next_page_directory(
     1103            thread_get_current_thread(), thread);
     1104
     1105        if (newPageDirectory != 0) {
     1106            read_cr3(oldPageDirectory);
     1107            write_cr3(newPageDirectory);
     1108        }
     1109    }
     1110
     1111    // execute the command
     1112    {
     1113        DebuggedThreadSetter threadSetter(thread);
     1114        evaluate_debug_command(commandLine);
     1115    }
     1116
     1117    // reset the page directory
     1118    if (oldPageDirectory)
     1119        write_cr3(oldPageDirectory);
     1120
     1121    return 0;
     1122}
     1123
     1124
     1125status_t
     1126arch_debug_init(kernel_args *args)
     1127{
     1128    // at this stage, the debugger command system is alive
     1129
     1130    add_debugger_command("where", &stack_trace, "Same as \"sc\"");
     1131    add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
     1132    add_debugger_command("sc", &stack_trace,
     1133        "Stack crawl for current thread (or any other)");
     1134    add_debugger_command("iframe", &dump_iframes,
     1135        "Dump iframes for the specified thread");
     1136    add_debugger_command("call", &show_call, "Show call with arguments");
     1137    add_debugger_command_etc("in_context", &cmd_in_context,
     1138        "Executes a command in the context of a given thread",
     1139        "<thread ID> <command> ...\n"
     1140        "Executes a command in the context of a given thread.\n",
     1141        B_KDEBUG_DONT_PARSE_ARGUMENTS);
     1142
     1143    return B_NO_ERROR;
     1144}
     1145
     1146int32
     1147arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
     1148    int32 skipIframes, int32 skipFrames, uint32 flags)
     1149{
     1150    // Keep skipping normal stack frames until we've skipped the iframes we're
     1151    // supposed to skip.
     1152    if (skipIframes > 0)
     1153        skipFrames = INT_MAX;
     1154
     1155    struct thread* thread = thread_get_current_thread();
     1156    int32 count = 0;
     1157    addr_t rbp = x86_64_read_rbp();
     1158    bool onKernelStack = true;
     1159
     1160    while (rbp != 0 && count < maxCount) {
     1161        onKernelStack = onKernelStack
     1162            && is_kernel_stack_address(thread, rbp);
     1163        if (!onKernelStack && (flags & STACK_TRACE_USER) == 0)
     1164            break;
     1165
     1166        addr_t rip;
     1167        addr_t nextRbp;
     1168
     1169        if (onKernelStack && is_iframe(thread, rbp)) {
     1170            struct iframe *frame = (struct iframe*)rbp;
     1171            rip = frame->rip;
     1172            nextRbp = frame->rbp;
     1173
     1174            if (skipIframes > 0) {
     1175                if (--skipIframes == 0)
     1176                    skipFrames = 0;
     1177            }
     1178        } else {
     1179            if (get_next_frame_no_debugger(rbp, &nextRbp, &rip) != B_OK)
     1180                break;
     1181        }
     1182
     1183        if (skipFrames <= 0
     1184            && ((flags & STACK_TRACE_KERNEL) != 0 || onKernelStack)) {
     1185            returnAddresses[count++] = rip;
     1186        } else
     1187            skipFrames--;
     1188
     1189        rbp = nextRbp;
     1190    }
     1191
     1192    return count;
     1193}
  • src/system/kernel/arch/x86_64/arch_cpu.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2007, François Revol, revol@free.fr.
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
     9 * Distributed under the terms of the MIT License.
     10 *
     11 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     12 * Distributed under the terms of the NewOS License.
     13 */
     14
     15
     16#include <cpu.h>
     17
     18#include <string.h>
     19#include <stdlib.h>
     20#include <stdio.h>
     21
     22#include <ACPI.h>
     23
     24#include <boot_device.h>
     25#include <commpage.h>
     26#include <debug.h>
     27#include <elf.h>
     28#include <smp.h>
     29#include <tls.h>
     30#include <vm/vm.h>
     31#include <vm/vm_types.h>
     32#include <vm/VMAddressSpace.h>
     33
     34#include <arch_system_info.h>
     35//#include <arch/x86/selector.h>
     36#include <boot/kernel_args.h>
     37
     38#include "interrupts.h"
     39
     40
     41#define CR0_CACHE_DISABLE       (1UL << 30)
     42#define CR0_NOT_WRITE_THROUGH       (1UL << 29)
     43#define CR0_FPU_EMULATION       (1UL << 2)
     44#define CR0_MONITOR_FPU         (1UL << 1)
     45
     46#define CR4_OS_FXSR         (1UL << 9)
     47#define CR4_OS_XMM_EXCEPTION        (1UL << 10)
     48
     49struct set_mtrrs_parameter {
     50    const x86_64_mtrr_info*     infos;
     51    uint32              count;
     52    uint8               defaultType;
     53};
     54
     55
     56void (*gX86SwapFPUFunc)(void *oldState, const void *newState);
     57
     58segment_descriptor *gGDT = NULL;
     59
     60static uint32 sCpuRendezvous;
     61static uint32 sCpuRendezvous2;
     62static uint32 sCpuRendezvous3;
     63
     64/* Some specials for the double fault handler */
     65static uint8* sDoubleFaultStacks;
     66static const size_t kDoubleFaultStackSize = 4096;   // size per CPU
     67
     68static x86_64_cpu_module_info *sCpuModule;
     69
     70
     71extern "C" void memcpy_generic(void* dest, const void* source, size_t count);
     72extern int memcpy_generic_end;
     73extern "C" void memset_generic(void* dest, int value, size_t count);
     74extern int memset_generic_end;
     75
     76
     77x86_64_optimized_functions gOptimizedFunctions = {
     78    memcpy_generic,
     79    &memcpy_generic_end,
     80    memset_generic,
     81    &memset_generic_end
     82};
     83
     84
     85void*
     86x86_64_get_double_fault_stack(int32 cpu, size_t* _size)
     87{
     88    *_size = kDoubleFaultStackSize;
     89    return sDoubleFaultStacks + kDoubleFaultStackSize * cpu;
     90}
     91
     92
     93/*! Returns the index of the current CPU. Can only be called from the double
     94    fault handler.
     95*/
     96int64
     97x86_64_double_fault_get_cpu(void)
     98{
     99    uint64 stack = x86_64_read_rbp();
     100    return (stack - (uint64)sDoubleFaultStacks) / kDoubleFaultStackSize;
     101}
     102
     103
     104void*
     105x86_64_set_tss_and_kstack(addr_t kstack)
     106{
     107    get_cpu_struct()->arch.tss.sp0 = kstack;
     108    return (void*)kstack;
     109}
     110
     111
     112/* TODO: Check code. Fix eax names and bitwidths  */
     113static int
     114detect_cpu(int currentCPU)
     115{
     116    cpu_ent *cpu = get_cpu_struct();
     117    char vendorString[17];
     118    cpuid_info cpuid;
     119
     120    // clear out the cpu info data
     121    cpu->arch.vendor = VENDOR_UNKNOWN;
     122    cpu->arch.vendor_name = "UNKNOWN VENDOR";
     123    cpu->arch.feature[FEATURE_COMMON] = 0;
     124    cpu->arch.feature[FEATURE_EXT] = 0;
     125    cpu->arch.feature[FEATURE_EXT_AMD] = 0;
     126    cpu->arch.model_name[0] = 0;
     127
     128    // print some fun data
     129    get_current_cpuid(&cpuid, 0);
     130
     131    // build the vendor string
     132    memset(vendorString, 0, sizeof(vendorString));
     133    memcpy(vendorString, cpuid.eax_0.vendor_id, sizeof(cpuid.eax_0.vendor_id));
     134
     135    // get the family, model, stepping
     136    get_current_cpuid(&cpuid, 1);
     137    cpu->arch.type = cpuid.eax_1.type;
     138    cpu->arch.family = cpuid.eax_1.family;
     139    cpu->arch.extended_family = cpuid.eax_1.extended_family;
     140    cpu->arch.model = cpuid.eax_1.model;
     141    cpu->arch.extended_model = cpuid.eax_1.extended_model;
     142    cpu->arch.stepping = cpuid.eax_1.stepping;
     143    dprintf("CPU %d: type %d family %d extended_family %d model %d "
     144        "extended_model %d stepping %d, string '%s'\n",
     145        currentCPU, cpu->arch.type, cpu->arch.family,
     146        cpu->arch.extended_family, cpu->arch.model,
     147        cpu->arch.extended_model, cpu->arch.stepping, vendorString);
     148
     149    // figure out what vendor we have here
     150
     151    for (int32 i = 0; i < VENDOR_NUM; i++) {
     152        if (vendor_info[i].ident_string[0]
     153            && !strcmp(vendorString, vendor_info[i].ident_string[0])) {
     154            cpu->arch.vendor = (x86_vendors)i;
     155            cpu->arch.vendor_name = vendor_info[i].vendor;
     156            break;
     157        }
     158        if (vendor_info[i].ident_string[1]
     159            && !strcmp(vendorString, vendor_info[i].ident_string[1])) {
     160            cpu->arch.vendor = (x86_vendors)i;
     161            cpu->arch.vendor_name = vendor_info[i].vendor;
     162            break;
     163        }
     164    }
     165
     166    // see if we can get the model name
     167    get_current_cpuid(&cpuid, 0x80000000);
     168    if (cpuid.eax_0.max_eax >= 0x80000004) {
     169        // build the model string (need to swap ecx/edx data before copying)
     170        unsigned int temp;
     171        memset(cpu->arch.model_name, 0, sizeof(cpu->arch.model_name));
     172
     173        get_current_cpuid(&cpuid, 0x80000002);
     174        temp = cpuid.regs.edx;
     175        cpuid.regs.edx = cpuid.regs.ecx;
     176        cpuid.regs.ecx = temp;
     177        memcpy(cpu->arch.model_name, cpuid.as_chars, sizeof(cpuid.as_chars));
     178
     179        get_current_cpuid(&cpuid, 0x80000003);
     180        temp = cpuid.regs.edx;
     181        cpuid.regs.edx = cpuid.regs.ecx;
     182        cpuid.regs.ecx = temp;
     183        memcpy(cpu->arch.model_name + 16, cpuid.as_chars,
     184            sizeof(cpuid.as_chars));
     185
     186        get_current_cpuid(&cpuid, 0x80000004);
     187        temp = cpuid.regs.edx;
     188        cpuid.regs.edx = cpuid.regs.ecx;
     189        cpuid.regs.ecx = temp;
     190        memcpy(cpu->arch.model_name + 32, cpuid.as_chars,
     191            sizeof(cpuid.as_chars));
     192
     193        // some cpus return a right-justified string
     194        int32 i = 0;
     195        while (cpu->arch.model_name[i] == ' ')
     196            i++;
     197        if (i > 0) {
     198            memmove(cpu->arch.model_name, &cpu->arch.model_name[i],
     199                strlen(&cpu->arch.model_name[i]) + 1);
     200        }
     201
     202        dprintf("CPU %d: vendor '%s' model name '%s'\n",
     203            currentCPU, cpu->arch.vendor_name, cpu->arch.model_name);
     204    } else {
     205        strcpy(cpu->arch.model_name, "unknown");
     206    }
     207
     208    // load feature bits
     209    get_current_cpuid(&cpuid, 1);
     210    cpu->arch.feature[FEATURE_COMMON] = cpuid.eax_1.features; // edx
     211    cpu->arch.feature[FEATURE_EXT] = cpuid.eax_1.extended_features; // ecx
     212    if (cpu->arch.vendor == VENDOR_AMD) {
     213        get_current_cpuid(&cpuid, 0x80000001);
     214        cpu->arch.feature[FEATURE_EXT_AMD] = cpuid.regs.edx; // edx
     215    }
     216
     217#if DUMP_FEATURE_STRING
     218    dump_feature_string(currentCPU, cpu);
     219#endif
     220
     221    return 0;
     222}
     223
     224/*
     225static void
     226init_double_fault(int cpuNum)
     227{
     228    // set up the double fault TSS
     229    struct tss *tss = &gCPU[cpuNum].arch.double_fault_tss;
     230
     231    memset(tss, 0, sizeof(struct tss));
     232    size_t stackSize;
     233    tss->sp0 = (uint64)x86_64_get_double_fault_stack(cpuNum, &stackSize);
     234    tss->sp0 += stackSize;
     235    tss->ss0 = KERNEL_DATA_SEG;
     236    read_cr3(tss->cr3);
     237        // copy the current cr3 to the double fault cr3
     238    tss->rip = (uint64)&double_fault;
     239    tss->es = KERNEL_DATA_SEG;
     240    tss->cs = KERNEL_CODE_SEG;
     241    tss->ss = KERNEL_DATA_SEG;
     242    tss->rsp = tss->sp0;
     243    tss->ds = KERNEL_DATA_SEG;
     244    tss->fs = KERNEL_DATA_SEG;
     245    tss->gs = KERNEL_DATA_SEG;
     246    tss->ldt_seg_selector = 0;
     247    tss->io_map_base = sizeof(struct tss);
     248
     249    // add TSS descriptor for this new TSS
     250    uint16 tssSegmentDescriptorIndex = DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum;
     251    set_tss_descriptor(&gGDT[tssSegmentDescriptorIndex],
     252        (addr_t)tss, sizeof(struct tss));
     253
     254    x86_64_set_task_gate(cpuNum, 8, tssSegmentDescriptorIndex << 3);
     255}
     256*/
     257
     258status_t
     259arch_cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
     260{
     261    x86_64_write_cr0(x86_64_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU));
     262    gX86SwapFPUFunc = x86_64_fnsave_swap;
     263#if 0   
     264/* TODO: Once x86_64 kernel is more stable enable SMP code */
     265    // On SMP system we want to synchronize the CPUs' TSCs, so system_time()
     266    // will return consistent values.
     267    if (smp_get_num_cpus() > 1) {
     268        // let the first CPU prepare the rendezvous point
     269        if (cpu == 0)
     270            sTSCSyncRendezvous = smp_get_num_cpus() - 1;
     271
     272        // One CPU after the other will drop out of this loop and be caught by
     273        // the loop below, until the last CPU (0) gets there. Save for +/- a few
     274        // cycles the CPUs should pass the second loop at the same time.
     275        while (sTSCSyncRendezvous != cpu) {
     276        }
     277
     278        sTSCSyncRendezvous = cpu - 1;
     279
     280        while (sTSCSyncRendezvous != -1) {
     281        }
     282
     283        // reset TSC to 0
     284        x86_write_msr(IA32_MSR_TSC, 0);
     285    }
     286#endif
     287    return B_OK;
     288}
     289
     290
     291/*! Disable CPU caches, and invalidate them. */
     292static void
     293disable_caches()
     294{
     295    x86_64_write_cr0((x86_64_read_cr0() | CR0_CACHE_DISABLE)
     296        & ~CR0_NOT_WRITE_THROUGH);
     297    wbinvd();
     298    arch_cpu_global_TLB_invalidate();
     299}
     300
     301
     302/*! Invalidate CPU caches, and enable them. */
     303static void
     304enable_caches()
     305{
     306    wbinvd();
     307    arch_cpu_global_TLB_invalidate();
     308    x86_64_write_cr0(x86_64_read_cr0()
     309        & ~(CR0_CACHE_DISABLE | CR0_NOT_WRITE_THROUGH));
     310}
     311
     312
     313
     314static void
     315init_mtrrs(void *_unused, int cpu)
     316{
     317    // wait until all CPUs have arrived here
     318    smp_cpu_rendezvous(&sCpuRendezvous, cpu);
     319
     320    // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU
     321    // that initiated the call_all_cpus() from doing that again and clearing
     322    // sCpuRendezvous2 before the last CPU has actually left the loop in
     323    // smp_cpu_rendezvous();
     324    if (cpu == 0)
     325        atomic_set((vint32*)&sCpuRendezvous3, 0);
     326
     327    disable_caches();
     328
     329    sCpuModule->init_mtrrs();
     330
     331    enable_caches();
     332
     333    // wait until all CPUs have arrived here
     334    smp_cpu_rendezvous(&sCpuRendezvous2, cpu);
     335    smp_cpu_rendezvous(&sCpuRendezvous3, cpu);
     336}
     337
     338
     339uint32
     340x86_64_count_mtrrs(void)
     341{
     342    if (sCpuModule == NULL)
     343        return 0;
     344
     345    return sCpuModule->count_mtrrs();
     346}
     347
     348
     349extern "C" void
     350init_sse(void)
     351{
     352    // enable OS support for SSE
     353    x86_64_write_cr4(x86_64_read_cr4() | CR4_OS_FXSR | CR4_OS_XMM_EXCEPTION);
     354    x86_64_write_cr0(x86_64_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU));
     355
     356    gX86SwapFPUFunc = x86_64_fxsave_swap;
     357}
     358
     359
     360static void
     361load_tss(int cpu)
     362{
     363    short seg = ((TSS_BASE_SEGMENT + cpu) << 3) | DPL_KERNEL;
     364    asm("movw  %0, %%ax;"
     365        "ltr %%ax;" : : "r" (seg) : "rax");
     366}
     367
     368
     369status_t
     370arch_cpu_init_percpu(kernel_args *args, int cpuid)
     371{
     372    detect_cpu(cpuid);
     373
     374    // load the TSS for this cpu
     375    // note the main cpu gets initialized in arch_cpu_init_post_vm()
     376    if (cpuid != 0) {
     377        load_tss(cpuid);
     378
     379        // set the IDT
     380        struct {
     381            uint16  limit;
     382            void*   address;    //TODO: Should GDT/IDT have 64bit address or 32bit address in longmode
     383        } _PACKED descriptor = {
     384            256 * 8 - 1,    // 256 descriptors, 8 bytes each (-1 for "limit")
     385            x86_64_get_idt(cpuid)
     386        };
     387
     388        asm volatile("lidt  %0" : : "m"(descriptor));
     389    }
     390
     391    return 0;
     392}
     393
     394
     395status_t
     396arch_cpu_init(kernel_args *args)
     397{
     398    // init the TSC -> system_time() conversion factors
     399
     400    uint32 conversionFactor = args->arch_args.system_time_cv_factor;
     401    uint64 conversionFactorNsecs = (uint64)conversionFactor * 1000;
     402
     403
     404    if (conversionFactorNsecs >> 32 != 0) {
     405        // the TSC frequency is < 1 GHz, which forces us to shift the factor
     406        __x86_64_setup_system_time(conversionFactor, conversionFactorNsecs >> 16,
     407            true);
     408    } else {
     409        // the TSC frequency is >= 1 GHz
     410        __x86_64_setup_system_time(conversionFactor, conversionFactorNsecs, false);
     411    }
     412
     413    return B_OK;
     414}
     415
     416
     417status_t
     418arch_cpu_init_post_vm(kernel_args *args)
     419{
     420/*  uint32 i;
     421
     422    // account for the segment descriptors
     423    gGDT = (segment_descriptor *)args->arch_args.vir_gdt;
     424    create_area("gdt", (void **)&gGDT, B_EXACT_ADDRESS, B_PAGE_SIZE,
     425        B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
     426
     427    // currently taken out of the build, because it's not yet used (and assumes
     428    // (a fixed number of used GDT entries)
     429    //i386_selector_init(gGDT);  // pass the new gdt
     430
     431    // allocate an area for the double fault stacks
     432    virtual_address_restrictions virtualRestrictions = {};
     433    virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
     434    physical_address_restrictions physicalRestrictions = {};
     435    create_area_etc(B_SYSTEM_TEAM, "double fault stacks",
     436        kDoubleFaultStackSize * smp_get_num_cpus(), B_FULL_LOCK,
     437        B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
     438        &virtualRestrictions, &physicalRestrictions,
     439        (void**)&sDoubleFaultStacks);
     440
     441    X86PagingStructures* kernelPagingStructures
     442        = static_cast<X86VMTranslationMap*>(
     443            VMAddressSpace::Kernel()->TranslationMap())->PagingStructures();
     444
     445    // setup task-state segments
     446    for (i = 0; i < args->num_cpus; i++) {
     447        // initialize the regular and double fault tss stored in the per-cpu
     448        // structure
     449        memset(&gCPU[i].arch.tss, 0, sizeof(struct tss));
     450        gCPU[i].arch.tss.ss0 = KERNEL_DATA_SEG;
     451        gCPU[i].arch.tss.io_map_base = sizeof(struct tss);
     452
     453        // add TSS descriptor for this new TSS
     454        set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i],
     455            (addr_t)&gCPU[i].arch.tss, sizeof(struct tss));
     456
     457        // initialize the double fault tss
     458        init_double_fault(i);
     459
     460        // init active translation map
     461        gCPU[i].arch.active_paging_structures = kernelPagingStructures;
     462        kernelPagingStructures->AddReference();
     463    }
     464
     465    // set the current hardware task on cpu 0
     466    load_tss(0);
     467
     468    // setup TLS descriptors (one for every CPU)
     469
     470    for (i = 0; i < args->num_cpus; i++) {
     471        set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE,
     472            DT_DATA_WRITEABLE, DPL_USER);
     473    }
     474
     475    // setup SSE2/3 support
     476    init_sse();
     477
     478*/  return B_OK;
     479}
     480
     481status_t
     482arch_cpu_init_post_modules(kernel_args *args)
     483{
     484    // initialize CPU module
     485
     486    void *cookie = open_module_list("cpu");
     487
     488    while (true) {
     489        char name[B_FILE_NAME_LENGTH];
     490        size_t nameLength = sizeof(name);
     491
     492        if (read_next_module_name(cookie, name, &nameLength) != B_OK
     493            || get_module(name, (module_info **)&sCpuModule) == B_OK)
     494            break;
     495    }
     496
     497    close_module_list(cookie);
     498
     499    // initialize MTRRs if available
     500    if (x86_64_count_mtrrs() > 0) {
     501        sCpuRendezvous = sCpuRendezvous2 = 0;
     502        call_all_cpus(&init_mtrrs, NULL);
     503    }
     504
     505    // get optimized functions from the CPU module
     506    if (sCpuModule != NULL && sCpuModule->get_optimized_functions != NULL) {
     507        x86_64_optimized_functions functions;
     508        memset(&functions, 0, sizeof(functions));
     509
     510        sCpuModule->get_optimized_functions(&functions);
     511
     512        if (functions.memcpy != NULL) {
     513            gOptimizedFunctions.memcpy = functions.memcpy;
     514            gOptimizedFunctions.memcpy_end = functions.memcpy_end;
     515        }
     516
     517        if (functions.memset != NULL) {
     518            gOptimizedFunctions.memset = functions.memset;
     519            gOptimizedFunctions.memset_end = functions.memset_end;
     520        }
     521    }
     522
     523    // put the optimized functions into the commpage
     524    size_t memcpyLen = (addr_t)gOptimizedFunctions.memcpy_end
     525        - (addr_t)gOptimizedFunctions.memcpy;
     526    fill_commpage_entry(COMMPAGE_ENTRY_X86_64_MEMCPY,
     527        (const void*)gOptimizedFunctions.memcpy, memcpyLen);
     528    size_t memsetLen = (addr_t)gOptimizedFunctions.memset_end
     529        - (addr_t)gOptimizedFunctions.memset;
     530    fill_commpage_entry(COMMPAGE_ENTRY_X86_64_MEMSET,
     531        (const void*)gOptimizedFunctions.memset, memsetLen);
     532
     533    // add the functions to the commpage image
     534    image_id image = get_commpage_image();
     535    elf_add_memory_image_symbol(image, "commpage_memcpy",
     536        ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_64_MEMCPY], memcpyLen,
     537        B_SYMBOL_TYPE_TEXT);
     538    elf_add_memory_image_symbol(image, "commpage_memset",
     539        ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_64_MEMSET], memsetLen,
     540        B_SYMBOL_TYPE_TEXT);
     541
     542    return B_OK;
     543}
     544
     545
     546void
     547arch_cpu_sync_icache(void *address, size_t len)
     548{
     549    // instruction cache is always consistent on x86 and x86_64
     550}
     551
     552
     553void
     554arch_cpu_memory_read_barrier(void)
     555{
     556    asm volatile ("lock;" : : : "memory");
     557    asm volatile ("add $0, 0(%%rsp);" : : : "memory");
     558}
     559
     560
     561void
     562arch_cpu_memory_write_barrier(void)
     563{
     564    asm volatile ("lock;" : : : "memory");
     565    asm volatile ("add $0, 0(%%rsp);" : : : "memory");
     566}
     567
     568
     569void
     570arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
     571{
     572    int64 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
     573    while (num_pages-- >= 0) {
     574        invalidate_TLB(start);
     575        start += B_PAGE_SIZE;
     576    }
     577}
     578
     579
     580void
     581arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
     582{
     583    int i;
     584    for (i = 0; i < num_pages; i++) {
     585        invalidate_TLB(pages[i]);
     586    }
     587}
     588
     589
     590void
     591arch_cpu_global_TLB_invalidate(void)
     592{
     593    uint32 flags = x86_64_read_cr4();
     594
     595    if (flags & IA32_CR4_GLOBAL_PAGES) {
     596        // disable and reenable the global pages to flush all TLBs regardless
     597        // of the global page bit
     598        x86_64_write_cr4(flags & ~IA32_CR4_GLOBAL_PAGES);
     599        x86_64_write_cr4(flags | IA32_CR4_GLOBAL_PAGES);
     600    } else {
     601        cpu_status state = disable_interrupts();
     602        arch_cpu_user_TLB_invalidate();
     603        restore_interrupts(state);
     604    }
     605}
     606
     607
     608ssize_t
     609arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
     610{
     611    int fromLength = 0;
     612    addr_t oldFaultHandler = *faultHandler;
     613
     614    // this check is to trick the gcc4 compiler and have it keep the error label
     615    if (to == NULL && size > 0)
     616        goto error;
     617
     618    *faultHandler = (addr_t)&&error;
     619
     620    if (size > 0) {
     621        to[--size] = '\0';
     622        // copy
     623        for ( ; size; size--, fromLength++, to++, from++) {
     624            if ((*to = *from) == '\0')
     625                break;
     626        }
     627    }
     628    // count any leftover from chars
     629    while (*from++ != '\0') {
     630        fromLength++;
     631    }
     632
     633    *faultHandler = oldFaultHandler;
     634    return fromLength;
     635
     636error:
     637    *faultHandler = oldFaultHandler;
     638    return B_BAD_ADDRESS;
     639}
     640
     641
     642status_t
     643arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
     644{
     645    char *xs = (char *)s;
     646    addr_t oldFaultHandler = *faultHandler;
     647
     648    // this check is to trick the gcc4 compiler and have it keep the error label
     649    if (s == NULL)
     650        goto error;
     651
     652    *faultHandler = (addr_t)&&error;
     653
     654    while (count--)
     655        *xs++ = c;
     656
     657    *faultHandler = oldFaultHandler;
     658    return 0;
     659
     660error:
     661    *faultHandler = oldFaultHandler;
     662    return B_BAD_ADDRESS;
     663}
     664
     665
     666static status_t
     667acpi_shutdown(bool reboot)
     668{
     669    if (debug_debugger_running() || !are_interrupts_enabled())
     670        return B_ERROR;
     671
     672    acpi_module_info* acpi;
     673    if (get_module(B_ACPI_MODULE_NAME, (module_info**)&acpi) != B_OK)
     674        return B_NOT_SUPPORTED;
     675
     676    status_t status;
     677    if (reboot) {
     678        status = acpi->reboot();
     679    } else {
     680        status = acpi->prepare_sleep_state(ACPI_POWER_STATE_OFF, NULL, 0);
     681        if (status == B_OK) {
     682            //cpu_status state = disable_interrupts();
     683            status = acpi->enter_sleep_state(ACPI_POWER_STATE_OFF);
     684            //restore_interrupts(state);
     685        }
     686    }
     687
     688    put_module(B_ACPI_MODULE_NAME);
     689    return status;
     690}
     691
     692
     693status_t
     694arch_cpu_shutdown(bool reboot)
     695{
     696    // Make sure we run on the boot CPU (apparently needed for ACPI)
     697    _user_set_cpu_enabled(0, true);
     698    for (int32 cpu = 1; cpu < smp_get_num_cpus(); cpu++) {
     699        _user_set_cpu_enabled(cpu, false);
     700    }
     701    thread_yield(true);
     702
     703    if (acpi_shutdown(reboot) == B_OK)
     704        return B_OK;
     705
     706    /* TODO: once APM code is in place shutdown apm here if !reboot */
     707
     708    cpu_status state = disable_interrupts();
     709
     710    // try to reset the system using the keyboard controller
     711    out8(0xfe, 0x64);
     712
     713    // Give some time to the controller to do its job (0.5s)
     714    snooze(500000);
     715
     716    // if that didn't help, try it this way
     717//  reboot();   /* TODO: write a function for arch_x86_64.S */
     718
     719    restore_interrupts(state);
     720    return B_ERROR;
     721}
     722
     723
     724void
     725arch_cpu_idle(void)
     726{
     727    asm("hlt");
     728}
     729
     730
     731static void
     732set_mtrrs(void* _parameter, int cpu)
     733{
     734    set_mtrrs_parameter* parameter = (set_mtrrs_parameter*)_parameter;
     735
     736    // wait until all CPUs have arrived here
     737    smp_cpu_rendezvous(&sCpuRendezvous, cpu);
     738
     739    // One CPU has to reset sCpuRendezvous3 -- it is needed to prevent the CPU
     740    // that initiated the call_all_cpus() from doing that again and clearing
     741    // sCpuRendezvous2 before the last CPU has actually left the loop in
     742    // smp_cpu_rendezvous();
     743    if (cpu == 0)
     744        atomic_set((vint32*)&sCpuRendezvous3, 0);
     745
     746    disable_caches();
     747
     748    sCpuModule->set_mtrrs(parameter->defaultType, parameter->infos,
     749        parameter->count);
     750
     751    enable_caches();
     752
     753    // wait until all CPUs have arrived here
     754    smp_cpu_rendezvous(&sCpuRendezvous2, cpu);
     755    smp_cpu_rendezvous(&sCpuRendezvous3, cpu);
     756}
     757
     758
     759void
     760x86_64_set_mtrrs(uint8 defaultType, const x86_64_mtrr_info* infos, uint32 count)
     761{
     762    if (sCpuModule == NULL)
     763        return;
     764
     765    struct set_mtrrs_parameter parameter;
     766    parameter.defaultType = defaultType;
     767    parameter.infos = infos;
     768    parameter.count = count;
     769
     770    sCpuRendezvous = sCpuRendezvous2 = 0;
     771    call_all_cpus(&set_mtrrs, &parameter);
     772}
  • src/system/kernel/arch/x86_64/interrupts.h

     
     1/*
     2 * Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     6 * Distributed under the terms of the NewOS License.
     7 */
     8#ifndef _KERNEL_ARCH_x86_64_INTERRUPTS_H
     9#define _KERNEL_ARCH_x86_64_INTERRUPTS_H
     10
     11
     12#ifdef __cplusplus
     13extern "C" {
     14#endif
     15
     16void trap0();void trap1();void trap2();void trap3();void trap4();void trap5();
     17void trap6();void trap7();void trap9();void trap10();void trap11();
     18void trap12();void trap13();void trap14();void trap16();void trap17();
     19void trap18();void trap19();
     20
     21void trap32();void trap33();void trap34();void trap35();void trap36();
     22void trap37();void trap38();void trap39();void trap40();void trap41();
     23void trap42();void trap43();void trap44();void trap45();void trap46();
     24void trap47();void trap48();void trap49();void trap50();void trap51();
     25void trap52();void trap53();void trap54();void trap55();void trap56();
     26void trap57();void trap58();void trap59();void trap60();void trap61();
     27void trap62();void trap63();void trap64();void trap65();void trap66();
     28void trap67();void trap68();void trap69();void trap70();void trap71();
     29void trap72();void trap73();void trap74();void trap75();void trap76();
     30void trap77();void trap78();void trap79();void trap80();void trap81();
     31void trap82();void trap83();void trap84();void trap85();void trap86();
     32void trap87();void trap88();void trap89();void trap90();void trap91();
     33void trap92();void trap93();void trap94();void trap95();void trap96();
     34void trap97();
     35
     36void double_fault();    // int 8
     37void trap14_double_fault();
     38
     39void trap98();
     40void trap99();
     41
     42void trap100();void trap101();void trap102();void trap103();void trap104();
     43void trap105();void trap106();void trap107();void trap108();void trap109();
     44void trap110();void trap111();void trap112();void trap113();void trap114();
     45void trap115();void trap116();void trap117();void trap118();void trap119();
     46void trap120();void trap121();void trap122();void trap123();void trap124();
     47void trap125();void trap126();void trap127();void trap128();void trap129();
     48void trap130();void trap131();void trap132();void trap133();void trap134();
     49void trap135();void trap136();void trap137();void trap138();void trap139();
     50void trap140();void trap141();void trap142();void trap143();void trap144();
     51void trap145();void trap146();void trap147();void trap148();void trap149();
     52void trap150();void trap151();void trap152();void trap153();void trap154();
     53void trap155();void trap156();void trap157();void trap158();void trap159();
     54void trap160();void trap161();void trap162();void trap163();void trap164();
     55void trap165();void trap166();void trap167();void trap168();void trap169();
     56void trap170();void trap171();void trap172();void trap173();void trap174();
     57void trap175();void trap176();void trap177();void trap178();void trap179();
     58void trap180();void trap181();void trap182();void trap183();void trap184();
     59void trap185();void trap186();void trap187();void trap188();void trap189();
     60void trap190();void trap191();void trap192();void trap193();void trap194();
     61void trap195();void trap196();void trap197();void trap198();void trap199();
     62void trap200();void trap201();void trap202();void trap203();void trap204();
     63void trap205();void trap206();void trap207();void trap208();void trap209();
     64void trap210();void trap211();void trap212();void trap213();void trap214();
     65void trap215();void trap216();void trap217();void trap218();void trap219();
     66void trap220();void trap221();void trap222();void trap223();void trap224();
     67void trap225();void trap226();void trap227();void trap228();void trap229();
     68void trap230();void trap231();void trap232();void trap233();void trap234();
     69void trap235();void trap236();void trap237();void trap238();void trap239();
     70void trap240();void trap241();void trap242();void trap243();void trap244();
     71void trap245();void trap246();void trap247();void trap248();void trap249();
     72void trap250();
     73
     74void trap251();void trap252();void trap253();void trap254();void trap255();
     75
     76#ifdef __cplusplus
     77}
     78#endif
     79
     80#endif  /* _KERNEL_ARCH_x86_64_INTERRUPTS_H */
  • src/system/kernel/arch/x86_64/paging/X86_64VMTranslationMap.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     5 * Distributed under the terms of the MIT License.
     6 *
     7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     8 * Distributed under the terms of the NewOS License.
     9 */
     10
     11
     12#include "paging/X86_64VMTranslationMap.h"
     13
     14#include <int.h>
     15#include <slab/Slab.h>
     16#include <thread.h>
     17#include <util/AutoLock.h>
     18#include <vm/vm_page.h>
     19#include <vm/VMAddressSpace.h>
     20#include <vm/VMCache.h>
     21
     22#include "paging/X86_64PagingMethod.h"
     23#include "paging/X86_64PagingStructures.h"
     24#include "paging/x86_64_physical_page_mapper.h"
     25
     26
     27//#define TRACE_X86_64_VM_TRANSLATION_MAP
     28#ifdef TRACE_X86_64_VM_TRANSLATION_MAP
     29#   define TRACE(x...) dprintf(x)
     30#else
     31#   define TRACE(x...) ;
     32#endif
     33
     34
     35X86_64VMTranslationMap::X86_64VMTranslationMap()
     36    :
     37    fPagingStructures(NULL)
     38{
     39}
     40
     41
     42X86_64VMTranslationMap::~X86_64VMTranslationMap()
     43{
     44    if (fPagingStructures == NULL)
     45        return;
     46
     47    if (fPageMapper != NULL)
     48        fPageMapper->Delete();
     49
     50    // cycle through and free all of the user space page tables
     51
     52    STATIC_ASSERT(KERNEL_BASE == 0x80000000 && KERNEL_SIZE == 0x80000000);
     53        // assuming 1-1 split of the address space
     54
     55    for (uint32 k = 0; k < 2; k++) {
     56        page_directory_entry* pageDir
     57            = fPagingStructures->VirtualPageDirs()[k];
     58        if (pageDir == NULL)
     59            continue;
     60
     61        for (uint32 i = 0; i < kPageDirEntryCount; i++) {
     62            if ((pageDir[i] & X86_64_PDE_PRESENT) != 0) {
     63                phys_addr_t address = pageDir[i] & X86_64_PDE_ADDRESS_MASK;
     64                vm_page* page = vm_lookup_page(address / B_PAGE_SIZE);
     65                if (page == NULL)
     66                    panic("X86_64VMTranslationMap::~X86_64VMTranslationMap: "
     67                        "didn't find page table page: page address: %#"
     68                        B_PRIxPHYSADDR ", virtual base: %#" B_PRIxADDR "\n",
     69                        address,
     70                        (k * kPageDirEntryCount + i) * kPageTableRange);
     71                DEBUG_PAGE_ACCESS_START(page);
     72                vm_page_set_state(page, PAGE_STATE_FREE);
     73            }
     74        }
     75    }
     76
     77    fPagingStructures->RemoveReference();
     78}
     79
     80
     81status_t
     82X86_64VMTranslationMap::Init(bool kernel)
     83{
     84    TRACE("X86_64VMTranslationMap::Init()\n");
     85
     86    X86_64VMTranslationMap::Init(kernel);
     87
     88    fPagingStructures = new(std::nothrow) X86_64PagingStructures;
     89    if (fPagingStructures == NULL)
     90        return B_NO_MEMORY;
     91
     92    X86_64PagingMethod* method = X86_64PagingMethod::Method();
     93
     94    if (kernel) {
     95        // kernel
     96        // get the physical page mapper
     97        fPageMapper = method->KernelPhysicalPageMapper();
     98
     99        // we already know the kernel pgdir mapping
     100        fPagingStructures->Init(method->KernelVirtualPageDirPointerTable(),
     101            method->KernelPhysicalPageDirPointerTable(), NULL,
     102            method->KernelVirtualPageDirs(), method->KernelPhysicalPageDirs());
     103    } else {
     104        // user
     105        // allocate a physical page mapper
     106        status_t error = method->PhysicalPageMapper()
     107            ->CreateTranslationMapPhysicalPageMapper(&fPageMapper);
     108        if (error != B_OK)
     109            return error;
     110
     111        // The following code assumes that the kernel address space occupies the
     112        // upper half of the virtual address space. This simplifies things a
     113        // lot, since it allows us to just use the upper two page directories
     114        // of the kernel and create two new lower page directories for the
     115        // userland.
     116        STATIC_ASSERT(KERNEL_BASE == 0x80000000 && KERNEL_SIZE == 0x80000000);
     117
     118        // allocate the page directories (both at once)
     119        page_directory_entry* virtualPageDirs[4];
     120        phys_addr_t physicalPageDirs[4];
     121        virtualPageDirs[0] = (page_directory_entry*)memalign(B_PAGE_SIZE,
     122            2 * B_PAGE_SIZE);
     123        if (virtualPageDirs[0] == NULL)
     124            return B_NO_MEMORY;
     125        virtualPageDirs[1] = virtualPageDirs[0] + kPageTableEntryCount;
     126
     127        // clear the userland page directories
     128        memset(virtualPageDirs[0], 0, 2 * B_PAGE_SIZE);
     129
     130        // use the upper two kernel page directories
     131        for (int32 i = 2; i < 4; i++) {
     132            virtualPageDirs[i] = method->KernelVirtualPageDirs()[i];
     133            physicalPageDirs[i] = method->KernelPhysicalPageDirs()[i];
     134        }
     135
     136        // look up the page directories' physical addresses
     137        for (int32 i = 0; i < 2; i++) {
     138            vm_get_page_mapping(VMAddressSpace::KernelID(),
     139                (addr_t)virtualPageDirs[i], &physicalPageDirs[i]);
     140        }
     141
     142        // allocate the PDPT -- needs to have a 32 bit physical address
     143        phys_addr_t physicalPDPT;
     144        void* pdptHandle;
     145        page_directory_pointer_table_entry* pdpt
     146            = (page_directory_pointer_table_entry*)
     147                method->Allocate32BitPage(physicalPDPT, pdptHandle);
     148        if (pdpt == NULL)
     149            free(virtualPageDirs[0]);
     150
     151        // init the PDPT entries
     152        for (int32 i = 0; i < 4; i++) {
     153            pdpt[i] = (physicalPageDirs[i] & X86_64_PDPTE_ADDRESS_MASK)
     154                | X86_64_PDPTE_PRESENT;
     155        }
     156
     157        // init the paging structures
     158        fPagingStructures->Init(pdpt, physicalPDPT, pdptHandle, virtualPageDirs,
     159            physicalPageDirs);
     160    }
     161
     162    return B_OK;
     163}
     164
     165
     166size_t
     167X86_64VMTranslationMap::MaxPagesNeededToMap(addr_t start, addr_t end) const
     168{
     169    // If start == 0, the actual base address is not yet known to the caller and
     170    // we shall assume the worst case.
     171    if (start == 0) {
     172        // offset the range so it has the worst possible alignment
     173        start = kPageTableRange - B_PAGE_SIZE;
     174        end += kPageTableRange - B_PAGE_SIZE;
     175    }
     176
     177    return end / kPageTableRange + 1 - start / kPageTableRange;
     178}
     179
     180
     181status_t
     182X86_64VMTranslationMap::Map(addr_t virtualAddress, phys_addr_t physicalAddress,
     183    uint32 attributes, uint32 memoryType, vm_page_reservation* reservation)
     184{
     185    TRACE("X86_64VMTranslationMap::Map(): %#" B_PRIxADDR " -> %#" B_PRIxPHYSADDR
     186        "\n", virtualAddress, physicalAddress);
     187
     188    // check to see if a page table exists for this range
     189    page_directory_entry* pageDirEntry
     190        = X86_64PagingMethod::PageDirEntryForAddress(
     191            fPagingStructures->VirtualPageDirs(), virtualAddress);
     192    if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     193        // we need to allocate a page table
     194        vm_page *page = vm_page_allocate_page(reservation,
     195            PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
     196
     197        DEBUG_PAGE_ACCESS_END(page);
     198
     199        phys_addr_t physicalPageTable
     200            = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
     201
     202        TRACE("X86_64VMTranslationMap::Map(): asked for free page for "
     203            "page table: %#" B_PRIxPHYSADDR "\n", physicalPageTable);
     204
     205        // put it in the page dir
     206        X86_64PagingMethod::PutPageTableInPageDir(pageDirEntry,
     207            physicalPageTable,
     208            attributes
     209                | ((attributes & B_USER_PROTECTION) != 0
     210                        ? B_WRITE_AREA : B_KERNEL_WRITE_AREA));
     211
     212        fMapCount++;
     213    }
     214
     215    // now, fill in the page table entry
     216    struct thread* thread = thread_get_current_thread();
     217    ThreadCPUPinner pinner(thread);
     218
     219    page_table_entry* pageTable
     220        = (page_table_entry*)fPageMapper->GetPageTableAt(
     221            *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     222    page_table_entry* entry = pageTable
     223        + virtualAddress / B_PAGE_SIZE % kPageTableEntryCount;
     224
     225    ASSERT_PRINT((*entry & X86_64_PTE_PRESENT) == 0,
     226        "virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx64,
     227        virtualAddress, *entry);
     228
     229    X86_64PagingMethod::PutPageTableEntryInTable(entry, physicalAddress,
     230        attributes, memoryType, fIsKernelMap);
     231
     232    pinner.Unlock();
     233
     234    // Note: We don't need to invalidate the TLB for this address, as previously
     235    // the entry was not present and the TLB doesn't cache those entries.
     236
     237    fMapCount++;
     238
     239    return 0;
     240}
     241
     242
     243status_t
     244X86_64VMTranslationMap::Unmap(addr_t start, addr_t end)
     245{
     246    start = ROUNDDOWN(start, B_PAGE_SIZE);
     247    if (start >= end)
     248        return B_OK;
     249
     250    TRACE("X86_64VMTranslationMap::Unmap(): %#" B_PRIxADDR " - %#" B_PRIxADDR
     251        "\n", start, end);
     252
     253    do {
     254        page_directory_entry* pageDirEntry
     255            = X86_64PagingMethod::PageDirEntryForAddress(
     256                fPagingStructures->VirtualPageDirs(), start);
     257        if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     258            // no page table here, move the start up to access the next page
     259            // table
     260            start = ROUNDUP(start + 1, kPageTableRange);
     261            continue;
     262        }
     263
     264        struct thread* thread = thread_get_current_thread();
     265        ThreadCPUPinner pinner(thread);
     266
     267        page_table_entry* pageTable
     268            = (page_table_entry*)fPageMapper->GetPageTableAt(
     269                *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     270
     271        uint32 index = start / B_PAGE_SIZE % kPageTableEntryCount;
     272        for (; index < kPageTableEntryCount && start < end;
     273                index++, start += B_PAGE_SIZE) {
     274            if ((pageTable[index] & X86_64_PTE_PRESENT) == 0) {
     275                // page mapping not valid
     276                continue;
     277            }
     278
     279            TRACE("X86_64VMTranslationMap::Unmap(): removing page %#"
     280                B_PRIxADDR "\n", start);
     281
     282            page_table_entry oldEntry
     283                = X86_64PagingMethod::ClearPageTableEntryFlags(
     284                    &pageTable[index], X86_64_PTE_PRESENT);
     285            fMapCount--;
     286
     287            if ((oldEntry & X86_64_PTE_ACCESSED) != 0) {
     288                // Note, that we only need to invalidate the address, if the
     289                // accessed flags was set, since only then the entry could have
     290                // been in any TLB.
     291                InvalidatePage(start);
     292            }
     293        }
     294    } while (start != 0 && start < end);
     295
     296    return B_OK;
     297}
     298
     299
     300/*! Caller must have locked the cache of the page to be unmapped.
     301    This object shouldn't be locked.
     302*/
     303status_t
     304X86_64VMTranslationMap::UnmapPage(VMArea* area, addr_t address,
     305    bool updatePageQueue)
     306{
     307    ASSERT(address % B_PAGE_SIZE == 0);
     308
     309    page_directory_entry* pageDirEntry
     310        = X86_64PagingMethod::PageDirEntryForAddress(
     311            fPagingStructures->VirtualPageDirs(), address);
     312
     313    TRACE("X86_64VMTranslationMap::UnmapPage(%#" B_PRIxADDR ")\n", address);
     314
     315    RecursiveLocker locker(fLock);
     316
     317    if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0)
     318        return B_ENTRY_NOT_FOUND;
     319
     320    ThreadCPUPinner pinner(thread_get_current_thread());
     321
     322    page_table_entry* pageTable
     323        = (page_table_entry*)fPageMapper->GetPageTableAt(
     324            *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     325
     326    page_table_entry oldEntry = X86_64PagingMethod::ClearPageTableEntry(
     327        &pageTable[address / B_PAGE_SIZE % kPageTableEntryCount]);
     328
     329    pinner.Unlock();
     330
     331    if ((oldEntry & X86_64_PTE_PRESENT) == 0) {
     332        // page mapping not valid
     333        return B_ENTRY_NOT_FOUND;
     334    }
     335
     336    fMapCount--;
     337
     338    if ((oldEntry & X86_64_PTE_ACCESSED) != 0) {
     339        // Note, that we only need to invalidate the address, if the
     340        // accessed flags was set, since only then the entry could have been
     341        // in any TLB.
     342        InvalidatePage(address);
     343
     344        Flush();
     345
     346        // NOTE: Between clearing the page table entry and Flush() other
     347        // processors (actually even this processor with another thread of the
     348        // same team) could still access the page in question via their cached
     349        // entry. We can obviously lose a modified flag in this case, with the
     350        // effect that the page looks unmodified (and might thus be recycled),
     351        // but is actually modified.
     352        // In most cases this is harmless, but for vm_remove_all_page_mappings()
     353        // this is actually a problem.
     354        // Interestingly FreeBSD seems to ignore this problem as well
     355        // (cf. pmap_remove_all()), unless I've missed something.
     356    }
     357
     358    locker.Detach();
     359        // PageUnmapped() will unlock for us
     360
     361    PageUnmapped(area, (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
     362        (oldEntry & X86_64_PTE_ACCESSED) != 0,
     363        (oldEntry & X86_64_PTE_DIRTY) != 0, updatePageQueue);
     364
     365    return B_OK;
     366}
     367
     368
     369void
     370X86_64VMTranslationMap::UnmapPages(VMArea* area, addr_t base, size_t size,
     371    bool updatePageQueue)
     372{
     373    if (size == 0)
     374        return;
     375
     376    addr_t start = base;
     377    addr_t end = base + size - 1;
     378
     379    TRACE("X86_64VMTranslationMap::UnmapPages(%p, %#" B_PRIxADDR ", %#"
     380        B_PRIxADDR ")\n", area, start, end);
     381
     382    VMAreaMappings queue;
     383
     384    RecursiveLocker locker(fLock);
     385
     386    do {
     387        page_directory_entry* pageDirEntry
     388            = X86_64PagingMethod::PageDirEntryForAddress(
     389                fPagingStructures->VirtualPageDirs(), start);
     390        if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     391            // no page table here, move the start up to access the next page
     392            // table
     393            start = ROUNDUP(start + 1, kPageTableRange);
     394            continue;
     395        }
     396
     397        struct thread* thread = thread_get_current_thread();
     398        ThreadCPUPinner pinner(thread);
     399
     400        page_table_entry* pageTable
     401            = (page_table_entry*)fPageMapper->GetPageTableAt(
     402                *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     403
     404        uint32 index = start / B_PAGE_SIZE % kPageTableEntryCount;
     405        for (; index < kPageTableEntryCount && start < end;
     406                index++, start += B_PAGE_SIZE) {
     407            page_table_entry oldEntry
     408                = X86_64PagingMethod::ClearPageTableEntry(&pageTable[index]);
     409            if ((oldEntry & X86_64_PTE_PRESENT) == 0)
     410                continue;
     411
     412            fMapCount--;
     413
     414            if ((oldEntry & X86_64_PTE_ACCESSED) != 0) {
     415                // Note, that we only need to invalidate the address, if the
     416                // accessed flags was set, since only then the entry could have
     417                // been in any TLB.
     418                InvalidatePage(start);
     419            }
     420
     421            if (area->cache_type != CACHE_TYPE_DEVICE) {
     422                // get the page
     423                vm_page* page = vm_lookup_page(
     424                    (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
     425                ASSERT(page != NULL);
     426
     427                DEBUG_PAGE_ACCESS_START(page);
     428
     429                // transfer the accessed/dirty flags to the page
     430                if ((oldEntry & X86_64_PTE_ACCESSED) != 0)
     431                    page->accessed = true;
     432                if ((oldEntry & X86_64_PTE_DIRTY) != 0)
     433                    page->modified = true;
     434
     435                // remove the mapping object/decrement the wired_count of the
     436                // page
     437                if (area->wiring == B_NO_LOCK) {
     438                    vm_page_mapping* mapping = NULL;
     439                    vm_page_mappings::Iterator iterator
     440                        = page->mappings.GetIterator();
     441                    while ((mapping = iterator.Next()) != NULL) {
     442                        if (mapping->area == area)
     443                            break;
     444                    }
     445
     446                    ASSERT(mapping != NULL);
     447
     448                    area->mappings.Remove(mapping);
     449                    page->mappings.Remove(mapping);
     450                    queue.Add(mapping);
     451                } else
     452                    page->DecrementWiredCount();
     453
     454                if (!page->IsMapped()) {
     455                    atomic_add(&gMappedPagesCount, -1);
     456
     457                    if (updatePageQueue) {
     458                        if (page->Cache()->temporary)
     459                            vm_page_set_state(page, PAGE_STATE_INACTIVE);
     460                        else if (page->modified)
     461                            vm_page_set_state(page, PAGE_STATE_MODIFIED);
     462                        else
     463                            vm_page_set_state(page, PAGE_STATE_CACHED);
     464                    }
     465                }
     466
     467                DEBUG_PAGE_ACCESS_END(page);
     468            }
     469        }
     470
     471        Flush();
     472            // flush explicitly, since we directly use the lock
     473    } while (start != 0 && start < end);
     474
     475    // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not
     476    // really critical here, as in all cases this method is used, the unmapped
     477    // area range is unmapped for good (resized/cut) and the pages will likely
     478    // be freed.
     479
     480    locker.Unlock();
     481
     482    // free removed mappings
     483    bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
     484    uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
     485        | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
     486    while (vm_page_mapping* mapping = queue.RemoveHead())
     487        object_cache_free(gPageMappingsObjectCache, mapping, freeFlags);
     488}
     489
     490
     491void
     492X86_64VMTranslationMap::UnmapArea(VMArea* area, bool deletingAddressSpace,
     493    bool ignoreTopCachePageFlags)
     494{
     495    if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
     496        X86_64VMTranslationMap::UnmapPages(area, area->Base(), area->Size(),
     497            true);
     498        return;
     499    }
     500
     501    bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
     502
     503    RecursiveLocker locker(fLock);
     504
     505    VMAreaMappings mappings;
     506    mappings.MoveFrom(&area->mappings);
     507
     508    for (VMAreaMappings::Iterator it = mappings.GetIterator();
     509            vm_page_mapping* mapping = it.Next();) {
     510        vm_page* page = mapping->page;
     511        page->mappings.Remove(mapping);
     512
     513        VMCache* cache = page->Cache();
     514
     515        bool pageFullyUnmapped = false;
     516        if (!page->IsMapped()) {
     517            atomic_add(&gMappedPagesCount, -1);
     518            pageFullyUnmapped = true;
     519        }
     520
     521        if (unmapPages || cache != area->cache) {
     522            addr_t address = area->Base()
     523                + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset);
     524
     525            page_directory_entry* pageDirEntry
     526                = X86_64PagingMethod::PageDirEntryForAddress(
     527                    fPagingStructures->VirtualPageDirs(), address);
     528            if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     529                panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
     530                    "has no page dir entry", page, area, address);
     531                continue;
     532            }
     533
     534            ThreadCPUPinner pinner(thread_get_current_thread());
     535
     536            page_table_entry* pageTable
     537                = (page_table_entry*)fPageMapper->GetPageTableAt(
     538                    *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     539            page_table_entry oldEntry
     540                = X86_64PagingMethod::ClearPageTableEntry(
     541                    &pageTable[address / B_PAGE_SIZE
     542                        % kPageTableEntryCount]);
     543
     544            pinner.Unlock();
     545
     546            if ((oldEntry & X86_64_PTE_PRESENT) == 0) {
     547                panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
     548                    "has no page table entry", page, area, address);
     549                continue;
     550            }
     551
     552            // transfer the accessed/dirty flags to the page and invalidate
     553            // the mapping, if necessary
     554            if ((oldEntry & X86_64_PTE_ACCESSED) != 0) {
     555                page->accessed = true;
     556
     557                if (!deletingAddressSpace)
     558                    InvalidatePage(address);
     559            }
     560
     561            if ((oldEntry & X86_64_PTE_DIRTY) != 0)
     562                page->modified = true;
     563
     564            if (pageFullyUnmapped) {
     565                DEBUG_PAGE_ACCESS_START(page);
     566
     567                if (cache->temporary)
     568                    vm_page_set_state(page, PAGE_STATE_INACTIVE);
     569                else if (page->modified)
     570                    vm_page_set_state(page, PAGE_STATE_MODIFIED);
     571                else
     572                    vm_page_set_state(page, PAGE_STATE_CACHED);
     573
     574                DEBUG_PAGE_ACCESS_END(page);
     575            }
     576        }
     577
     578        fMapCount--;
     579    }
     580
     581    Flush();
     582        // flush explicitely, since we directly use the lock
     583
     584    locker.Unlock();
     585
     586    bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
     587    uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
     588        | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
     589    while (vm_page_mapping* mapping = mappings.RemoveHead())
     590        object_cache_free(gPageMappingsObjectCache, mapping, freeFlags);
     591}
     592
     593
     594status_t
     595X86_64VMTranslationMap::Query(addr_t virtualAddress,
     596    phys_addr_t* _physicalAddress, uint32* _flags)
     597{
     598    // default the flags to not present
     599    *_flags = 0;
     600    *_physicalAddress = 0;
     601
     602    // get the page directory entry
     603    page_directory_entry* pageDirEntry
     604        = X86_64PagingMethod::PageDirEntryForAddress(
     605            fPagingStructures->VirtualPageDirs(), virtualAddress);
     606    if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     607        // no pagetable here
     608        return B_OK;
     609    }
     610
     611    // get the page table entry
     612    struct thread* thread = thread_get_current_thread();
     613    ThreadCPUPinner pinner(thread);
     614
     615    page_table_entry* pageTable
     616        = (page_table_entry*)fPageMapper->GetPageTableAt(
     617            *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     618    page_table_entry entry
     619        = pageTable[virtualAddress / B_PAGE_SIZE % kPageTableEntryCount];
     620
     621    pinner.Unlock();
     622
     623    *_physicalAddress = entry & X86_64_PTE_ADDRESS_MASK;
     624
     625    // translate the page state flags
     626    if ((entry & X86_64_PTE_USER) != 0) {
     627        *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
     628            | B_READ_AREA;
     629    }
     630
     631    *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
     632        | B_KERNEL_READ_AREA
     633        | ((entry & X86_64_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
     634        | ((entry & X86_64_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
     635        | ((entry & X86_64_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
     636
     637    TRACE("X86_64VMTranslationMap::Query(%#" B_PRIxADDR ") -> %#"
     638        B_PRIxPHYSADDR ":\n", *_physicalAddress, virtualAddress);
     639
     640    return B_OK;
     641}
     642
     643
     644status_t
     645X86_64VMTranslationMap::QueryInterrupt(addr_t virtualAddress,
     646    phys_addr_t* _physicalAddress, uint32* _flags)
     647{
     648    // default the flags to not present
     649    *_flags = 0;
     650    *_physicalAddress = 0;
     651
     652    // get the page directory entry
     653    page_directory_entry* pageDirEntry
     654        = X86_64PagingMethod::PageDirEntryForAddress(
     655            fPagingStructures->VirtualPageDirs(), virtualAddress);
     656    if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     657        // no pagetable here
     658        return B_OK;
     659    }
     660
     661    // get the page table entry
     662    page_table_entry* pageTable
     663        = (page_table_entry*)X86_64PagingMethod::Method()
     664            ->PhysicalPageMapper()->InterruptGetPageTableAt(
     665                *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     666    page_table_entry entry
     667        = pageTable[virtualAddress / B_PAGE_SIZE % kPageTableEntryCount];
     668
     669    *_physicalAddress = entry & X86_64_PTE_ADDRESS_MASK;
     670
     671    // translate the page state flags
     672    if ((entry & X86_64_PTE_USER) != 0) {
     673        *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
     674            | B_READ_AREA;
     675    }
     676
     677    *_flags |= ((entry & X86_64_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
     678        | B_KERNEL_READ_AREA
     679        | ((entry & X86_64_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
     680        | ((entry & X86_64_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
     681        | ((entry & X86_64_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
     682
     683    TRACE("X86_64VMTranslationMap::Query(%#" B_PRIxADDR ") -> %#"
     684        B_PRIxPHYSADDR ":\n", *_physicalAddress, virtualAddress);
     685
     686    return B_OK;
     687}
     688
     689
     690status_t
     691X86_64VMTranslationMap::Protect(addr_t start, addr_t end, uint32 attributes,
     692    uint32 memoryType)
     693{
     694    start = ROUNDDOWN(start, B_PAGE_SIZE);
     695    if (start >= end)
     696        return B_OK;
     697
     698    TRACE("X86_64VMTranslationMap::Protect(): %#" B_PRIxADDR " - %#" B_PRIxADDR
     699        ", attributes: %#" B_PRIx32 "\n", start, end, attributes);
     700
     701    // compute protection flags
     702    uint64 newProtectionFlags = 0;
     703    if ((attributes & B_USER_PROTECTION) != 0) {
     704        newProtectionFlags = X86_64_PTE_USER;
     705        if ((attributes & B_WRITE_AREA) != 0)
     706            newProtectionFlags |= X86_64_PTE_WRITABLE;
     707    } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
     708        newProtectionFlags = X86_64_PTE_WRITABLE;
     709
     710    do {
     711        page_directory_entry* pageDirEntry
     712            = X86_64PagingMethod::PageDirEntryForAddress(
     713                fPagingStructures->VirtualPageDirs(), start);
     714        if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     715            // no page table here, move the start up to access the next page
     716            // table
     717            start = ROUNDUP(start + 1, kPageTableRange);
     718            continue;
     719        }
     720
     721        struct thread* thread = thread_get_current_thread();
     722        ThreadCPUPinner pinner(thread);
     723
     724        page_table_entry* pageTable
     725            = (page_table_entry*)fPageMapper->GetPageTableAt(
     726                *pageDirEntry & X86_64_PDE_ADDRESS_MASK);
     727
     728        uint32 index = start / B_PAGE_SIZE % kPageTableEntryCount;
     729        for (; index < kPageTableEntryCount && start < end;
     730                index++, start += B_PAGE_SIZE) {
     731            page_table_entry entry = pageTable[index];
     732            if ((pageTable[index] & X86_64_PTE_PRESENT) == 0) {
     733                // page mapping not valid
     734                continue;
     735            }
     736
     737            TRACE("X86_64VMTranslationMap::Protect(): protect page %#"
     738                B_PRIxADDR "\n", start);
     739
     740            // set the new protection flags -- we want to do that atomically,
     741            // without changing the accessed or dirty flag
     742            page_table_entry oldEntry;
     743            while (true) {
     744                oldEntry = X86_64PagingMethod::TestAndSetPageTableEntry(
     745                    &pageTable[index],
     746                    (entry & ~(X86_64_PTE_PROTECTION_MASK
     747                            | X86_64_PTE_MEMORY_TYPE_MASK))
     748                        | newProtectionFlags
     749                        | X86_64PagingMethod::MemoryTypeToPageTableEntryFlags(
     750                            memoryType),
     751                    entry);
     752                if (oldEntry == entry)
     753                    break;
     754                entry = oldEntry;
     755            }
     756
     757            if ((oldEntry & X86_64_PTE_ACCESSED) != 0) {
     758                // Note, that we only need to invalidate the address, if the
     759                // accessed flag was set, since only then the entry could have been
     760                // in any TLB.
     761                InvalidatePage(start);
     762            }
     763        }
     764    } while (start != 0 && start < end);
     765
     766    return B_OK;
     767}
     768
     769
     770status_t
     771X86_64VMTranslationMap::ClearFlags(addr_t address, uint32 flags)
     772{
     773    page_directory_entry* pageDirEntry
     774        = X86_64PagingMethod::PageDirEntryForAddress(
     775            fPagingStructures->VirtualPageDirs(), address);
     776    if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0) {
     777        // no pagetable here
     778        return B_OK;
     779    }
     780
     781    uint64 flagsToClear = ((flags & PAGE_MODIFIED) ? X86_64_PTE_DIRTY : 0)
     782        | ((flags & PAGE_ACCESSED) ? X86_64_PTE_ACCESSED : 0);
     783
     784    struct thread* thread = thread_get_current_thread();
     785    ThreadCPUPinner pinner(thread);
     786
     787    page_table_entry* entry
     788        = (page_table_entry*)fPageMapper->GetPageTableAt(
     789                *pageDirEntry & X86_64_PDE_ADDRESS_MASK)
     790            + address / B_PAGE_SIZE % kPageTableEntryCount;
     791
     792    // clear out the flags we've been requested to clear
     793    page_table_entry oldEntry
     794        = X86_64PagingMethod::ClearPageTableEntryFlags(entry, flagsToClear);
     795
     796    pinner.Unlock();
     797
     798    if ((oldEntry & flagsToClear) != 0)
     799        InvalidatePage(address);
     800
     801    return B_OK;
     802}
     803
     804
     805bool
     806X86_64VMTranslationMap::ClearAccessedAndModified(VMArea* area, addr_t address,
     807    bool unmapIfUnaccessed, bool& _modified)
     808{
     809    ASSERT(address % B_PAGE_SIZE == 0);
     810
     811    TRACE("X86_64VMTranslationMap32Bit::ClearAccessedAndModified(%#" B_PRIxADDR
     812        ")\n", address);
     813
     814    page_directory_entry* pageDirEntry
     815        = X86_64PagingMethod::PageDirEntryForAddress(
     816            fPagingStructures->VirtualPageDirs(), address);
     817
     818    RecursiveLocker locker(fLock);
     819
     820    if ((*pageDirEntry & X86_64_PDE_PRESENT) == 0)
     821        return false;
     822
     823    ThreadCPUPinner pinner(thread_get_current_thread());
     824
     825    page_table_entry* entry
     826        = (page_table_entry*)fPageMapper->GetPageTableAt(
     827                *pageDirEntry & X86_64_PDE_ADDRESS_MASK)
     828            + address / B_PAGE_SIZE % kPageTableEntryCount;
     829
     830    // perform the deed
     831    page_table_entry oldEntry;
     832
     833    if (unmapIfUnaccessed) {
     834        while (true) {
     835            oldEntry = *entry;
     836            if ((oldEntry & X86_64_PTE_PRESENT) == 0) {
     837                // page mapping not valid
     838                return false;
     839            }
     840
     841            if (oldEntry & X86_64_PTE_ACCESSED) {
     842                // page was accessed -- just clear the flags
     843                oldEntry = X86_64PagingMethod::ClearPageTableEntryFlags(entry,
     844                    X86_64_PTE_ACCESSED | X86_64_PTE_DIRTY);
     845                break;
     846            }
     847
     848            // page hasn't been accessed -- unmap it
     849            if (X86_64PagingMethod::TestAndSetPageTableEntry(entry, 0, oldEntry)
     850                    == oldEntry) {
     851                break;
     852            }
     853
     854            // something changed -- check again
     855        }
     856    } else {
     857        oldEntry = X86_64PagingMethod::ClearPageTableEntryFlags(entry,
     858            X86_64_PTE_ACCESSED | X86_64_PTE_DIRTY);
     859    }
     860
     861    pinner.Unlock();
     862
     863    _modified = (oldEntry & X86_64_PTE_DIRTY) != 0;
     864
     865    if ((oldEntry & X86_64_PTE_ACCESSED) != 0) {
     866        // Note, that we only need to invalidate the address, if the
     867        // accessed flags was set, since only then the entry could have been
     868        // in any TLB.
     869        InvalidatePage(address);
     870        Flush();
     871
     872        return true;
     873    }
     874
     875    if (!unmapIfUnaccessed)
     876        return false;
     877
     878    // We have unmapped the address. Do the "high level" stuff.
     879
     880    fMapCount--;
     881
     882    locker.Detach();
     883        // UnaccessedPageUnmapped() will unlock for us
     884
     885    UnaccessedPageUnmapped(area,
     886        (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
     887
     888    return false;
     889}
     890
     891
     892/*! Acquires the map's recursive lock, and resets the invalidate pages counter
     893    in case it's the first locking recursion.
     894*/
     895bool
     896X86_64VMTranslationMap::Lock()
     897{
     898    TRACE("%p->X86_64VMTranslationMap::Lock()\n", this);
     899
     900    recursive_lock_lock(&fLock);
     901    if (recursive_lock_get_recursion(&fLock) == 1) {
     902        // we were the first one to grab the lock
     903        TRACE("clearing invalidated page count\n");
     904        fInvalidPagesCount = 0;
     905    }
     906
     907    return true;
     908}
     909
     910
     911/*! Unlocks the map, and, if we are actually losing the recursive lock,
     912    flush all pending changes of this map (ie. flush TLB caches as
     913    needed).
     914*/
     915void
     916X86_64VMTranslationMap::Unlock()
     917{
     918    TRACE("%p->X86_64VMTranslationMap::Unlock()\n", this);
     919
     920    if (recursive_lock_get_recursion(&fLock) == 1) {
     921        // we're about to release it for the last time
     922        Flush();
     923    }
     924
     925    recursive_lock_unlock(&fLock);
     926}
     927
     928
     929addr_t
     930X86_64VMTranslationMap::MappedSize() const
     931{
     932    return fMapCount;
     933}
     934
     935
     936void
     937X86_64VMTranslationMap::Flush()
     938{
     939    if (fInvalidPagesCount <= 0)
     940        return;
     941
     942    struct thread* thread = thread_get_current_thread();
     943    thread_pin_to_current_cpu(thread);
     944
     945    if (fInvalidPagesCount > PAGE_INVALIDATE_CACHE_SIZE) {
     946        // invalidate all pages
     947        TRACE("flush_tmap: %d pages to invalidate, invalidate all\n",
     948            fInvalidPagesCount);
     949
     950        if (fIsKernelMap) {
     951            arch_cpu_global_TLB_invalidate();
     952            smp_send_broadcast_ici(SMP_MSG_GLOBAL_INVALIDATE_PAGES, 0, 0, 0,
     953                NULL, SMP_MSG_FLAG_SYNC);
     954        } else {
     955            cpu_status state = disable_interrupts();
     956            arch_cpu_user_TLB_invalidate();
     957            restore_interrupts(state);
     958
     959            int cpu = smp_get_current_cpu();
     960            uint32 cpuMask = PagingStructures()->active_on_cpus
     961                & ~((uint32)1 << cpu);
     962            if (cpuMask != 0) {
     963                smp_send_multicast_ici(cpuMask, SMP_MSG_USER_INVALIDATE_PAGES,
     964                    0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
     965            }
     966        }
     967    } else {
     968        TRACE("flush_tmap: %d pages to invalidate, invalidate list\n",
     969            fInvalidPagesCount);
     970
     971        arch_cpu_invalidate_TLB_list(fInvalidPages, fInvalidPagesCount);
     972
     973        if (fIsKernelMap) {
     974            smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_LIST,
     975                (uint64)fInvalidPages, fInvalidPagesCount, 0, NULL,
     976                SMP_MSG_FLAG_SYNC);
     977        } else {
     978            int cpu = smp_get_current_cpu();
     979            uint32 cpuMask = PagingStructures()->active_on_cpus
     980                & ~((uint32)1 << cpu);
     981            if (cpuMask != 0) {
     982                smp_send_multicast_ici(cpuMask, SMP_MSG_INVALIDATE_PAGE_LIST,
     983                    (uint64)fInvalidPages, fInvalidPagesCount, 0, NULL,
     984                    SMP_MSG_FLAG_SYNC);
     985            }
     986        }
     987    }
     988    fInvalidPagesCount = 0;
     989
     990    thread_unpin_from_current_cpu(thread);
     991}
  • src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper.h

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     6 * Distributed under the terms of the MIT License.
     7 */
     8#ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_H
     9#define KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_H
     10
     11
     12#include <vm/VMTranslationMap.h>
     13
     14
     15struct kernel_args;
     16struct vm_translation_map_ops;
     17
     18
     19class TranslationMapPhysicalPageMapper {
     20public:
     21    virtual                     ~TranslationMapPhysicalPageMapper();
     22
     23    virtual void                Delete() = 0;
     24
     25    virtual void*               GetPageTableAt(phys_addr_t physicalAddress) = 0;
     26        // Must be invoked with thread pinned to current CPU.
     27};
     28
     29
     30class X86_64PhysicalPageMapper : public VMPhysicalPageMapper {
     31public:
     32    virtual                     ~X86_64PhysicalPageMapper();
     33
     34    virtual status_t            CreateTranslationMapPhysicalPageMapper(
     35                                    TranslationMapPhysicalPageMapper** _mapper)
     36                                        = 0;
     37
     38    virtual void*               InterruptGetPageTableAt(
     39                                    phys_addr_t physicalAddress) = 0;
     40};
     41
     42
     43#endif  // KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_H
  • src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper_large_memory.h

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     6 * Distributed under the terms of the MIT License.
     7 */
     8#ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_LARGE_MEMORY_H
     9#define KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_LARGE_MEMORY_H
     10
     11
     12#include <OS.h>
     13
     14#include <util/DoublyLinkedList.h>
     15
     16
     17class TranslationMapPhysicalPageMapper;
     18class X86_64PhysicalPageMapper;
     19struct kernel_args;
     20
     21
     22namespace X86_64LargePhysicalPageMapper {
     23
     24
     25struct PhysicalPageSlotPool;
     26
     27
     28struct PhysicalPageSlot {
     29    PhysicalPageSlot*           next;
     30    PhysicalPageSlotPool*           pool;
     31    addr_t                  address;
     32
     33    inline  void                Map(phys_addr_t physicalAddress);
     34};
     35
     36
     37struct PhysicalPageSlotPool : DoublyLinkedListLinkImpl<PhysicalPageSlotPool> {
     38
     39    virtual                 ~PhysicalPageSlotPool();
     40
     41    inline  bool                IsEmpty() const;
     42
     43    inline  PhysicalPageSlot*       GetSlot();
     44    inline  void                PutSlot(PhysicalPageSlot* slot);
     45
     46    virtual status_t            AllocatePool(PhysicalPageSlotPool*& _pool) = 0;
     47    virtual void                Map(phys_addr_t physicalAddress,
     48                                addr_t virtualAddress) = 0;
     49
     50protected:
     51    PhysicalPageSlot*           fSlots;
     52};
     53
     54
     55}
     56
     57
     58status_t large_memory_physical_page_ops_init(kernel_args* args,
     59    X86_64LargePhysicalPageMapper::PhysicalPageSlotPool* initialPool,
     60    X86_64PhysicalPageMapper*& _pageMapper,
     61    TranslationMapPhysicalPageMapper*& _kernelPageMapper);
     62
     63
     64#endif  // KERNEL_ARCH_X86_64_PAGING_X86_64_PHYSICAL_PAGE_MAPPER_LARGE_MEMORY_H
  • src/system/kernel/arch/x86_64/paging/X86_64VMTranslationMap.h

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Distributed under the terms of the MIT License.
     5 */
     6#ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_VM_TRANSLATION_MAP_H
     7#define KERNEL_ARCH_X86_64_PAGING_X86_64_VM_TRANSLATION_MAP_H
     8
     9
     10#include <vm/VMTranslationMap.h>
     11
     12
     13#define PAGE_INVALIDATE_CACHE_SIZE 64
     14
     15
     16struct X86_64PagingStructures;
     17class TranslationMapPhysicalPageMapper;
     18
     19
     20struct X86_64VMTranslationMap : VMTranslationMap {
     21                                X86_64VMTranslationMap();
     22    virtual                     ~X86_64VMTranslationMap();
     23
     24            status_t            Init(bool kernel);
     25
     26    virtual bool                Lock();
     27    virtual void                Unlock();
     28
     29    virtual addr_t              MappedSize() const;
     30
     31    virtual void                Flush();
     32
     33    inline  void                InvalidatePage(addr_t address);
     34
     35    inline  X86_64PagingStructures*     PagingStructures();
     36
     37    virtual size_t              MaxPagesNeededToMap(addr_t start,
     38                                    addr_t end) const;
     39
     40    virtual status_t            Map(addr_t virtualAddress,
     41                                    phys_addr_t physicalAddress,
     42                                    uint32 attributes, uint32 memoryType,
     43                                    vm_page_reservation* reservation);
     44    virtual status_t            Unmap(addr_t start, addr_t end);
     45
     46    virtual status_t            UnmapPage(VMArea* area, addr_t address,
     47                                    bool updatePageQueue);
     48    virtual void                UnmapPages(VMArea* area, addr_t base,
     49                                    size_t size, bool updatePageQueue);
     50    virtual void                UnmapArea(VMArea* area,
     51                                    bool deletingAddressSpace,
     52                                    bool ignoreTopCachePageFlags);
     53
     54    virtual status_t            Query(addr_t virtualAddress,
     55                                    phys_addr_t* _physicalAddress,
     56                                    uint32* _flags);
     57    virtual status_t            QueryInterrupt(addr_t virtualAddress,
     58                                    phys_addr_t* _physicalAddress,
     59                                    uint32* _flags);
     60
     61    virtual status_t            Protect(addr_t base, addr_t top,
     62                                    uint32 attributes, uint32 memoryType);
     63
     64    virtual status_t            ClearFlags(addr_t virtualAddress,
     65                                    uint32 flags);
     66
     67    virtual bool                ClearAccessedAndModified(
     68                                    VMArea* area, addr_t address,
     69                                    bool unmapIfUnaccessed,
     70                                    bool& _modified);
     71
     72protected:
     73    TranslationMapPhysicalPageMapper*   fPageMapper;
     74    int                 fInvalidPagesCount;
     75    addr_t                  fInvalidPages[PAGE_INVALIDATE_CACHE_SIZE];
     76    bool                    fIsKernelMap;
     77
     78    X86_64PagingStructures*         fPagingStructures;
     79};
     80
     81
     82void
     83X86_64VMTranslationMap::InvalidatePage(addr_t address)
     84{
     85    if (fInvalidPagesCount < PAGE_INVALIDATE_CACHE_SIZE)
     86        fInvalidPages[fInvalidPagesCount] = address;
     87
     88    fInvalidPagesCount++;
     89}
     90
     91inline  X86_64PagingStructures*
     92    X86_64VMTranslationMap::PagingStructures()
     93{
     94    return fPagingStructures;
     95}
     96
     97#endif  // KERNEL_ARCH_X86_64_PAGING_X86_64_VM_TRANSLATION_MAP_H
  • src/system/kernel/arch/x86_64/paging/X86_64PagingStructures.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     6 * Distributed under the terms of the MIT License.
     7 */
     8
     9
     10#include "paging/X86_64PagingStructures.h"
     11
     12#include <stdlib.h>
     13#include <string.h>
     14
     15#include <KernelExport.h>
     16
     17#include <int.h>
     18
     19#include "paging/X86_64PagingMethod.h"
     20
     21
     22X86_64PagingStructures::X86_64PagingStructures()
     23{
     24    fVirtualPageDirs[0] = NULL;
     25}
     26
     27
     28X86_64PagingStructures::~X86_64PagingStructures()
     29{
     30    // free the user page dirs
     31    free(fVirtualPageDirs[0]);
     32
     33    // free the PDPT page
     34    X86_64PagingMethod::Method()->Free32BitPage(fPageDirPointerTable,
     35        pgdir_phys, fPageDirPointerTableHandle);
     36}
     37
     38
     39void
     40X86_64PagingStructures::Init(
     41    page_directory_pointer_table_entry* virtualPDPT,
     42    phys_addr_t physicalPDPT, void* pdptHandle,
     43    page_directory_entry* const* virtualPageDirs,
     44    const phys_addr_t* physicalPageDirs)
     45{
     46    fPageDirPointerTable = virtualPDPT;
     47    pgdir_phys = physicalPDPT;
     48    fPageDirPointerTableHandle = pdptHandle;
     49    memcpy(fVirtualPageDirs, virtualPageDirs, sizeof(fVirtualPageDirs));
     50    memcpy(fPhysicalPageDirs, physicalPageDirs, sizeof(fPhysicalPageDirs));
     51}
     52
     53
     54void
     55X86_64PagingStructures::Delete()
     56{
     57    if (are_interrupts_enabled())
     58        delete this;
     59    else
     60        deferred_delete(this);
     61}
  • src/system/kernel/arch/x86_64/paging/paging.h

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     6 * Distributed under the terms of the MIT License.
     7 */
     8#ifndef KERNEL_ARCH_X86_64_PAGING_PAGING_H
     9#define KERNEL_ARCH_X86_64_PAGING_PAGING_H
     10
     11
     12#include <OS.h>
     13
     14
     15// page directory pointer table entry bits
     16#define X86_64_PDPTE_PRESENT            0x0000000000000001LL
     17#define X86_64_PDPTE_WRITE_THROUGH      0x0000000000000008LL
     18#define X86_64_PDPTE_CACHING_DISABLED   0x0000000000000010LL
     19#define X86_64_PDPTE_ADDRESS_MASK       0x000ffffffffff000LL
     20
     21// page directory entry bits
     22#define X86_64_PDE_PRESENT              0x0000000000000001LL
     23#define X86_64_PDE_WRITABLE         0x0000000000000002LL
     24#define X86_64_PDE_USER             0x0000000000000004LL
     25#define X86_64_PDE_WRITE_THROUGH        0x0000000000000008LL
     26#define X86_64_PDE_CACHING_DISABLED 0x0000000000000010LL
     27#define X86_64_PDE_ACCESSED         0x0000000000000020LL
     28#define X86_64_PDE_IGNORED1         0x0000000000000040LL
     29#define X86_64_PDE_LARGE_PAGE           0x0000000000000080LL
     30#define X86_64_PDE_IGNORED2         0x0000000000000100LL
     31#define X86_64_PDE_IGNORED3         0x0000000000000200LL
     32#define X86_64_PDE_IGNORED4         0x0000000000000400LL
     33#define X86_64_PDE_IGNORED5         0x0000000000000800LL
     34#define X86_64_PDE_ADDRESS_MASK     0x000ffffffffff000LL
     35#define X86_64_PDE_NOT_EXECUTABLE       0x8000000000000000LL
     36
     37// page table entry bits
     38#define X86_64_PTE_PRESENT              0x0000000000000001LL
     39#define X86_64_PTE_WRITABLE         0x0000000000000002LL
     40#define X86_64_PTE_USER             0x0000000000000004LL
     41#define X86_64_PTE_WRITE_THROUGH        0x0000000000000008LL
     42#define X86_64_PTE_CACHING_DISABLED 0x0000000000000010LL
     43#define X86_64_PTE_ACCESSED         0x0000000000000020LL
     44#define X86_64_PTE_DIRTY                0x0000000000000040LL
     45#define X86_64_PTE_PAT                  0x0000000000000080LL
     46#define X86_64_PTE_GLOBAL               0x0000000000000100LL
     47#define X86_64_PTE_IGNORED1         0x0000000000000200LL
     48#define X86_64_PTE_IGNORED2         0x0000000000000400LL
     49#define X86_64_PTE_IGNORED3         0x0000000000000800LL
     50#define X86_64_PTE_ADDRESS_MASK     0x000ffffffffff000LL
     51#define X86_64_PTE_NOT_EXECUTABLE       0x8000000000000000LL
     52#define X86_64_PTE_PROTECTION_MASK      (X86_64_PTE_WRITABLE \
     53                                            | X86_64_PTE_USER)
     54#define X86_64_PTE_MEMORY_TYPE_MASK (X86_64_PTE_WRITE_THROUGH \
     55                                            | X86_64_PTE_CACHING_DISABLED)
     56
     57
     58static const uint32 kPageDirEntryCount = 512;
     59static const uint32 kPageTableEntryCount = 512;
     60static const size_t kPageTableRange = kPageTableEntryCount * B_PAGE_SIZE;
     61static const size_t kPageDirRange
     62    = kPageDirEntryCount * kPageTableRange;
     63
     64
     65typedef uint64 page_directory_pointer_table_entry;
     66typedef uint64 page_directory_entry;
     67typedef uint64 page_table_entry;
     68
     69
     70#endif  // KERNEL_ARCH_X86_64_PAGING_PAGING_H
  • src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     6 * Distributed under the terms of the MIT License.
     7 */
     8
     9#include "paging/x86_64_physical_page_mapper.h"
     10
     11
     12TranslationMapPhysicalPageMapper::~TranslationMapPhysicalPageMapper()
     13{
     14}
     15
     16
     17X86_64PhysicalPageMapper::~X86_64PhysicalPageMapper()
     18{
     19}
  • src/system/kernel/arch/x86_64/paging/x86_64_physical_page_mapper_large_memory.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Distributed under the terms of the MIT License.
     4 *
     5 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     6 * Distributed under the terms of the MIT License.
     7 */
     8
     9
     10/*! Implementation of a physical page mapping strategy (PhysicalPageMapper,
     11    TranslationMapPhysicalPageMapper) suitable for machines with a lot of
     12    memory, i.e. more than we can afford to completely map into the kernel
     13    address space.
     14
     15    We allocate a single page table (one page) that can map 1024 pages and
     16    a corresponding virtual address space region (4 MB). Each of those 1024
     17    slots can map a physical page. We reserve a fixed amount of slots per CPU.
     18    They will be used for physical operations on that CPU (memset()/memcpy()
     19    and {get,put}_physical_page_current_cpu()). A few slots we reserve for each
     20    translation map (TranslationMapPhysicalPageMapper). Those will only be used
     21    with the translation map locked, mapping a page table page. The remaining
     22    slots remain in the global pool and are given out by get_physical_page().
     23
     24    When we run out of slots, we allocate another page table (and virtual
     25    address space region).
     26*/
     27
     28
     29#include "paging/x86_64_physical_page_mapper_large_memory.h"
     30
     31#include <new>
     32
     33#include <AutoDeleter.h>
     34
     35#include <cpu.h>
     36#include <lock.h>
     37#include <smp.h>
     38#include <util/AutoLock.h>
     39#include <vm/vm.h>
     40#include <vm/vm_types.h>
     41#include <vm/VMAddressSpace.h>
     42
     43#include "paging/x86_64_physical_page_mapper.h"
     44#include "paging/X86_64PagingStructures.h"
     45#include "paging/X86_64VMTranslationMap.h"
     46
     47
     48// The number of slots we reserve per translation map from mapping page tables.
     49// One slot would suffice, since the map is locked while mapping a page table,
     50// but we re-use several slots on a LRU-basis so that we can keep the mappings
     51// a little longer, thus avoiding re-mapping.
     52#define SLOTS_PER_TRANSLATION_MAP   4
     53
     54#define USER_SLOTS_PER_CPU  16
     55#define KERNEL_SLOTS_PER_CPU    16
     56#define TOTAL_SLOTS_PER_CPU (USER_SLOTS_PER_CPU + KERNEL_SLOTS_PER_CPU + 1)
     57
     58    // one slot is for use in interrupts
     59
     60
     61using X86_64LargePhysicalPageMapper::PhysicalPageSlot;
     62using X86_64LargePhysicalPageMapper::PhysicalPageSlotPool;
     63
     64
     65class PhysicalPageSlotQueue {
     66public:
     67                    PhysicalPageSlotQueue();
     68
     69    inline  PhysicalPageSlot*   GetSlot();
     70    inline  void            GetSlots(PhysicalPageSlot*& slot1,
     71                            PhysicalPageSlot*& slot2);
     72    inline  void            PutSlot(PhysicalPageSlot* slot);
     73    inline  void            PutSlots(PhysicalPageSlot* slot1,
     74                            PhysicalPageSlot* slot2);
     75
     76private:
     77    PhysicalPageSlot*       fSlots;
     78    ConditionVariable       fFreeSlotCondition;
     79    ConditionVariable       fFreeSlotsCondition;
     80};
     81
     82
     83struct PhysicalPageOpsCPUData {
     84    PhysicalPageSlotQueue       user;
     85        // Used when copying from/to user memory. This can cause a page fault
     86        // which might need to memcpy()/memset() a page when being handled.
     87    PhysicalPageSlotQueue       kernel;
     88        // Used when memset()ing or when memcpy()ing memory non-user memory.
     89    PhysicalPageSlot*       interruptSlot;
     90
     91    void                Init();
     92
     93private:
     94    static  PhysicalPageSlot*   _GetInitialSlot();
     95};
     96
     97
     98// #pragma mark -
     99
     100
     101class LargeMemoryTranslationMapPhysicalPageMapper
     102    : public TranslationMapPhysicalPageMapper {
     103public:
     104                    LargeMemoryTranslationMapPhysicalPageMapper();
     105    virtual             ~LargeMemoryTranslationMapPhysicalPageMapper();
     106
     107    status_t            Init();
     108
     109    virtual void            Delete();
     110
     111    virtual void*           GetPageTableAt(phys_addr_t physicalAddress);
     112
     113private:
     114    struct page_slot {
     115        PhysicalPageSlot*   slot;
     116        phys_addr_t     physicalAddress;
     117        cpu_mask_t      valid;
     118    };
     119
     120    page_slot           fSlots[SLOTS_PER_TRANSLATION_MAP];
     121    int32               fSlotCount; // must be a power of 2
     122    int32               fNextSlot;
     123};
     124
     125
     126class LargeMemoryPhysicalPageMapper : public X86_64PhysicalPageMapper {
     127public:
     128                    LargeMemoryPhysicalPageMapper();
     129
     130    status_t            Init(kernel_args* args,
     131                         PhysicalPageSlotPool* initialPool,
     132                         TranslationMapPhysicalPageMapper*&
     133                        _kernelPageMapper);
     134
     135    virtual status_t        CreateTranslationMapPhysicalPageMapper(
     136                        TranslationMapPhysicalPageMapper** _mapper);
     137
     138    virtual void*           InterruptGetPageTableAt(
     139                        phys_addr_t physicalAddress);
     140
     141    virtual status_t        GetPage(phys_addr_t physicalAddress,
     142                        addr_t* virtualAddress, void** handle);
     143    virtual status_t        PutPage(addr_t virtualAddress, void* handle);
     144
     145    virtual status_t        GetPageCurrentCPU(phys_addr_t physicalAddress,
     146                        addr_t* virtualAddress, void** handle);
     147    virtual status_t        PutPageCurrentCPU(addr_t virtualAddress,
     148                        void* handle);
     149
     150    virtual status_t        GetPageDebug(phys_addr_t physicalAddress,
     151                        addr_t* virtualAddress, void** handle);
     152    virtual status_t        PutPageDebug(addr_t virtualAddress,
     153                        void* handle);
     154
     155    virtual status_t        MemsetPhysical(phys_addr_t address, int value,
     156                        phys_size_t length);
     157    virtual status_t        MemcpyFromPhysical(void* to, phys_addr_t from,
     158                        size_t length, bool user);
     159    virtual status_t        MemcpyToPhysical(phys_addr_t to,
     160                        const void* from, size_t length, bool user);
     161    virtual void            MemcpyPhysicalPage(phys_addr_t to,
     162                        phys_addr_t from);
     163
     164    status_t            GetSlot(bool canWait,
     165                        PhysicalPageSlot*& slot);
     166    void                PutSlot(PhysicalPageSlot* slot);
     167
     168    inline  PhysicalPageSlotQueue*  GetSlotQueue(int32 cpu, bool user);
     169
     170private:
     171    typedef DoublyLinkedList<PhysicalPageSlotPool> PoolList;
     172
     173    mutex               fLock;
     174    PoolList            fEmptyPools;
     175    PoolList            fNonEmptyPools;
     176    PhysicalPageSlot* fDebugSlot;
     177    PhysicalPageSlotPool* fInitialPool;
     178    LargeMemoryTranslationMapPhysicalPageMapper fKernelMapper;
     179    PhysicalPageOpsCPUData fPerCPUData[B_MAX_CPU_COUNT];
     180};
     181
     182static LargeMemoryPhysicalPageMapper sPhysicalPageMapper;
     183
     184
     185// #pragma mark - PhysicalPageSlot / PhysicalPageSlotPool
     186
     187
     188inline void
     189PhysicalPageSlot::Map(phys_addr_t physicalAddress)
     190{
     191    pool->Map(physicalAddress, address);
     192}
     193
     194
     195PhysicalPageSlotPool::~PhysicalPageSlotPool()
     196{
     197}
     198
     199
     200inline bool
     201PhysicalPageSlotPool::IsEmpty() const
     202{
     203    return fSlots == NULL;
     204}
     205
     206
     207inline PhysicalPageSlot*
     208PhysicalPageSlotPool::GetSlot()
     209{
     210    PhysicalPageSlot* slot = fSlots;
     211    fSlots = slot->next;
     212    return slot;
     213}
     214
     215
     216inline void
     217PhysicalPageSlotPool::PutSlot(PhysicalPageSlot* slot)
     218{
     219    slot->next = fSlots;
     220    fSlots = slot;
     221}
     222
     223
     224// #pragma mark - PhysicalPageSlotQueue
     225
     226
     227PhysicalPageSlotQueue::PhysicalPageSlotQueue()
     228    :
     229    fSlots(NULL)
     230{
     231    fFreeSlotCondition.Init(this, "physical page ops slot queue");
     232    fFreeSlotsCondition.Init(this, "physical page ops slots queue");
     233}
     234
     235
     236PhysicalPageSlot*
     237PhysicalPageSlotQueue::GetSlot()
     238{
     239    InterruptsLocker locker;
     240
     241    // wait for a free slot to turn up
     242    while (fSlots == NULL) {
     243        ConditionVariableEntry entry;
     244        fFreeSlotCondition.Add(&entry);
     245        locker.Unlock();
     246        entry.Wait();
     247        locker.Lock();
     248    }
     249
     250    PhysicalPageSlot* slot = fSlots;
     251    fSlots = slot->next;
     252
     253    return slot;
     254}
     255
     256
     257void
     258PhysicalPageSlotQueue::GetSlots(PhysicalPageSlot*& slot1,
     259    PhysicalPageSlot*& slot2)
     260{
     261    InterruptsLocker locker;
     262
     263    // wait for two free slot to turn up
     264    while (fSlots == NULL || fSlots->next == NULL) {
     265        ConditionVariableEntry entry;
     266        fFreeSlotsCondition.Add(&entry);
     267        locker.Unlock();
     268        entry.Wait();
     269        locker.Lock();
     270    }
     271
     272    slot1 = fSlots;
     273    slot2 = slot1->next;
     274    fSlots = slot2->next;
     275}
     276
     277
     278void
     279PhysicalPageSlotQueue::PutSlot(PhysicalPageSlot* slot)
     280{
     281    InterruptsLocker locker;
     282
     283    slot->next = fSlots;
     284    fSlots = slot;
     285
     286    if (slot->next == NULL)
     287        fFreeSlotCondition.NotifyAll();
     288    else if (slot->next->next == NULL)
     289        fFreeSlotCondition.NotifyAll();
     290}
     291
     292
     293void
     294PhysicalPageSlotQueue::PutSlots(PhysicalPageSlot* slot1,
     295    PhysicalPageSlot* slot2)
     296{
     297    InterruptsLocker locker;
     298
     299    slot1->next = slot2;
     300    slot2->next = fSlots;
     301    fSlots = slot1;
     302
     303    if (slot2->next == NULL)
     304        fFreeSlotCondition.NotifyAll();
     305    else if (slot2->next->next == NULL)
     306        fFreeSlotCondition.NotifyAll();
     307}
     308
     309
     310// #pragma mark - PhysicalPageOpsCPUData
     311
     312
     313void
     314PhysicalPageOpsCPUData::Init()
     315{
     316    for (int32 i = 0; i < USER_SLOTS_PER_CPU; i++)
     317        user.PutSlot(_GetInitialSlot());
     318    for (int32 i = 0; i < KERNEL_SLOTS_PER_CPU; i++)
     319        kernel.PutSlot(_GetInitialSlot());
     320    interruptSlot = _GetInitialSlot();
     321}
     322
     323
     324/* static */ PhysicalPageSlot*
     325PhysicalPageOpsCPUData::_GetInitialSlot()
     326{
     327    PhysicalPageSlot* slot;
     328    status_t error = sPhysicalPageMapper.GetSlot(false, slot);
     329    if (error != B_OK) {
     330        panic("PhysicalPageOpsCPUData::Init(): Failed to get initial "
     331            "physical page slots! Probably too many CPUs.");
     332        return NULL;
     333    }
     334
     335    return slot;
     336}
     337
     338
     339// #pragma mark - LargeMemoryTranslationMapPhysicalPageMapper
     340
     341
     342LargeMemoryTranslationMapPhysicalPageMapper
     343    ::LargeMemoryTranslationMapPhysicalPageMapper()
     344    :
     345    fSlotCount(sizeof(fSlots) / sizeof(page_slot)),
     346    fNextSlot(0)
     347{
     348    memset(fSlots, 0, sizeof(fSlots));
     349}
     350
     351
     352LargeMemoryTranslationMapPhysicalPageMapper
     353    ::~LargeMemoryTranslationMapPhysicalPageMapper()
     354{
     355    // put our slots back to the global pool
     356    for (int32 i = 0; i < fSlotCount; i++) {
     357        if (fSlots[i].slot != NULL)
     358            sPhysicalPageMapper.PutSlot(fSlots[i].slot);
     359    }
     360}
     361
     362
     363status_t
     364LargeMemoryTranslationMapPhysicalPageMapper::Init()
     365{
     366    // get our slots from the global pool
     367    for (int32 i = 0; i < fSlotCount; i++) {
     368        status_t error = sPhysicalPageMapper.GetSlot(true, fSlots[i].slot);
     369        if (error != B_OK)
     370            return error;
     371
     372        // set to invalid physical address, so it won't be used accidentally
     373        fSlots[i].physicalAddress = ~(phys_addr_t)0;
     374    }
     375
     376    return B_OK;
     377}
     378
     379
     380void
     381LargeMemoryTranslationMapPhysicalPageMapper::Delete()
     382{
     383    delete this;
     384}
     385
     386
     387void*
     388LargeMemoryTranslationMapPhysicalPageMapper::GetPageTableAt(
     389    phys_addr_t physicalAddress)
     390{
     391    ASSERT(physicalAddress % B_PAGE_SIZE == 0);
     392
     393    int32 currentCPU = smp_get_current_cpu();
     394
     395    // maybe the address is already mapped
     396    for (int32 i = 0; i < fSlotCount; i++) {
     397        page_slot& slot = fSlots[i];
     398        if (slot.physicalAddress == physicalAddress) {
     399            fNextSlot = (i + 1) & (fSlotCount - 1);
     400            if ((slot.valid & (1 << currentCPU)) == 0) {
     401                // not valid on this CPU -- invalidate the TLB entry
     402                invalidate_TLB(slot.slot->address);
     403                slot.valid |= 1 << currentCPU;
     404            }
     405            return (void*)slot.slot->address;
     406        }
     407    }
     408
     409    // not found -- need to map a fresh one
     410    page_slot& slot = fSlots[fNextSlot];
     411    fNextSlot = (fNextSlot + 1) & (fSlotCount - 1);
     412
     413    slot.physicalAddress = physicalAddress;
     414    slot.slot->Map(physicalAddress);
     415    slot.valid = 1 << currentCPU;
     416
     417    return (void*)slot.slot->address;
     418}
     419
     420
     421// #pragma mark - LargeMemoryPhysicalPageMapper
     422
     423
     424LargeMemoryPhysicalPageMapper::LargeMemoryPhysicalPageMapper()
     425    :
     426    fInitialPool(NULL)
     427{
     428    mutex_init(&fLock, "large memory physical page mapper");
     429}
     430
     431
     432status_t
     433LargeMemoryPhysicalPageMapper::Init(kernel_args* args,
     434    PhysicalPageSlotPool* initialPool,
     435    TranslationMapPhysicalPageMapper*& _kernelPageMapper)
     436{
     437    fInitialPool = initialPool;
     438    fNonEmptyPools.Add(fInitialPool);
     439
     440    // get the debug slot
     441    GetSlot(true, fDebugSlot);
     442
     443    // init the kernel translation map physical page mapper
     444    status_t error = fKernelMapper.Init();
     445    if (error != B_OK) {
     446        panic("LargeMemoryPhysicalPageMapper::Init(): Failed to init "
     447            "kernel translation map physical page mapper!");
     448        return error;
     449    }
     450    _kernelPageMapper = &fKernelMapper;
     451
     452    // init the per-CPU data
     453    int32 cpuCount = smp_get_num_cpus();
     454    for (int32 i = 0; i < cpuCount; i++)
     455        fPerCPUData[i].Init();
     456
     457    return B_OK;
     458}
     459
     460
     461status_t
     462LargeMemoryPhysicalPageMapper::CreateTranslationMapPhysicalPageMapper(
     463    TranslationMapPhysicalPageMapper** _mapper)
     464{
     465    LargeMemoryTranslationMapPhysicalPageMapper* mapper
     466        = new(std::nothrow) LargeMemoryTranslationMapPhysicalPageMapper;
     467    if (mapper == NULL)
     468        return B_NO_MEMORY;
     469
     470    status_t error = mapper->Init();
     471    if (error != B_OK) {
     472        delete mapper;
     473        return error;
     474    }
     475
     476    *_mapper = mapper;
     477    return B_OK;
     478}
     479
     480
     481void*
     482LargeMemoryPhysicalPageMapper::InterruptGetPageTableAt(
     483    phys_addr_t physicalAddress)
     484{
     485    ASSERT(physicalAddress % B_PAGE_SIZE == 0);
     486
     487    PhysicalPageSlot* slot = fPerCPUData[smp_get_current_cpu()].interruptSlot;
     488    slot->Map(physicalAddress);
     489    return (void*)slot->address;
     490}
     491
     492
     493status_t
     494LargeMemoryPhysicalPageMapper::GetPage(phys_addr_t physicalAddress,
     495    addr_t* virtualAddress, void** handle)
     496{
     497    PhysicalPageSlot* slot;
     498    status_t error = GetSlot(true, slot);
     499    if (error != B_OK)
     500        return error;
     501
     502    slot->Map(physicalAddress);
     503
     504    *handle = slot;
     505    *virtualAddress = slot->address + physicalAddress % B_PAGE_SIZE;
     506
     507    smp_send_broadcast_ici(SMP_MSG_INVALIDATE_PAGE_RANGE, *virtualAddress,
     508        *virtualAddress, 0, NULL, SMP_MSG_FLAG_SYNC);
     509
     510    return B_OK;
     511}
     512
     513
     514status_t
     515LargeMemoryPhysicalPageMapper::PutPage(addr_t virtualAddress, void* handle)
     516{
     517    PutSlot((PhysicalPageSlot*)handle);
     518    return B_OK;
     519}
     520
     521
     522status_t
     523LargeMemoryPhysicalPageMapper::GetPageCurrentCPU(phys_addr_t physicalAddress,
     524    addr_t* virtualAddress, void** handle)
     525{
     526    // get a slot from the per-cpu user pool
     527    PhysicalPageSlotQueue& slotQueue
     528        = fPerCPUData[smp_get_current_cpu()].user;
     529    PhysicalPageSlot* slot = slotQueue.GetSlot();
     530    slot->Map(physicalAddress);
     531
     532    *virtualAddress = slot->address + physicalAddress % B_PAGE_SIZE;
     533    *handle = slot;
     534
     535    return B_OK;
     536}
     537
     538
     539status_t
     540LargeMemoryPhysicalPageMapper::PutPageCurrentCPU(addr_t virtualAddress,
     541    void* handle)
     542{
     543    // return the slot to the per-cpu user pool
     544    PhysicalPageSlotQueue& slotQueue
     545        = fPerCPUData[smp_get_current_cpu()].user;
     546    slotQueue.PutSlot((PhysicalPageSlot*)handle);
     547    return B_OK;
     548}
     549
     550
     551status_t
     552LargeMemoryPhysicalPageMapper::GetPageDebug(phys_addr_t physicalAddress,
     553    addr_t* virtualAddress, void** handle)
     554{
     555    fDebugSlot->Map(physicalAddress);
     556
     557    *handle = fDebugSlot;
     558    *virtualAddress = fDebugSlot->address + physicalAddress % B_PAGE_SIZE;
     559    return B_OK;
     560}
     561
     562
     563status_t
     564LargeMemoryPhysicalPageMapper::PutPageDebug(addr_t virtualAddress, void* handle)
     565{
     566    return B_OK;
     567}
     568
     569
     570status_t
     571LargeMemoryPhysicalPageMapper::MemsetPhysical(phys_addr_t address, int value,
     572    phys_size_t length)
     573{
     574    phys_addr_t pageOffset = address % B_PAGE_SIZE;
     575
     576    struct thread* thread = thread_get_current_thread();
     577    ThreadCPUPinner _(thread);
     578
     579    PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num,
     580        false);
     581    PhysicalPageSlot* slot = slotQueue->GetSlot();
     582
     583    while (length > 0) {
     584        slot->Map(address - pageOffset);
     585
     586        size_t toSet = min_c(length, B_PAGE_SIZE - pageOffset);
     587        memset((void*)(slot->address + pageOffset), value, toSet);
     588
     589        length -= toSet;
     590        address += toSet;
     591        pageOffset = 0;
     592    }
     593
     594    slotQueue->PutSlot(slot);
     595
     596    return B_OK;
     597}
     598
     599
     600status_t
     601LargeMemoryPhysicalPageMapper::MemcpyFromPhysical(void* _to, phys_addr_t from,
     602    size_t length, bool user)
     603{
     604    uint8* to = (uint8*)_to;
     605    phys_addr_t pageOffset = from % B_PAGE_SIZE;
     606
     607    struct thread* thread = thread_get_current_thread();
     608    ThreadCPUPinner _(thread);
     609
     610    PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, user);
     611    PhysicalPageSlot* slot = slotQueue->GetSlot();
     612
     613    status_t error = B_OK;
     614
     615    while (length > 0) {
     616        size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset);
     617
     618        slot->Map(from - pageOffset);
     619
     620        if (user) {
     621            error = user_memcpy(to, (void*)(slot->address + pageOffset),
     622                toCopy);
     623            if (error != B_OK)
     624                break;
     625        } else
     626            memcpy(to, (void*)(slot->address + pageOffset), toCopy);
     627
     628        to += toCopy;
     629        from += toCopy;
     630        length -= toCopy;
     631        pageOffset = 0;
     632    }
     633
     634    slotQueue->PutSlot(slot);
     635
     636    return error;
     637}
     638
     639
     640status_t
     641LargeMemoryPhysicalPageMapper::MemcpyToPhysical(phys_addr_t to,
     642    const void* _from, size_t length, bool user)
     643{
     644    const uint8* from = (const uint8*)_from;
     645    phys_addr_t pageOffset = to % B_PAGE_SIZE;
     646
     647    struct thread* thread = thread_get_current_thread();
     648    ThreadCPUPinner _(thread);
     649
     650    PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num, user);
     651    PhysicalPageSlot* slot = slotQueue->GetSlot();
     652
     653    status_t error = B_OK;
     654
     655    while (length > 0) {
     656        size_t toCopy = min_c(length, B_PAGE_SIZE - pageOffset);
     657
     658        slot->Map(to - pageOffset);
     659
     660        if (user) {
     661            error = user_memcpy((void*)(slot->address + pageOffset), from,
     662                toCopy);
     663            if (error != B_OK)
     664                break;
     665        } else
     666            memcpy((void*)(slot->address + pageOffset), from, toCopy);
     667
     668        to += toCopy;
     669        from += toCopy;
     670        length -= toCopy;
     671        pageOffset = 0;
     672    }
     673
     674    slotQueue->PutSlot(slot);
     675
     676    return error;
     677}
     678
     679
     680void
     681LargeMemoryPhysicalPageMapper::MemcpyPhysicalPage(phys_addr_t to,
     682    phys_addr_t from)
     683{
     684    struct thread* thread = thread_get_current_thread();
     685    ThreadCPUPinner _(thread);
     686
     687    PhysicalPageSlotQueue* slotQueue = GetSlotQueue(thread->cpu->cpu_num,
     688        false);
     689    PhysicalPageSlot* fromSlot;
     690    PhysicalPageSlot* toSlot;
     691    slotQueue->GetSlots(fromSlot, toSlot);
     692
     693    fromSlot->Map(from);
     694    toSlot->Map(to);
     695
     696    memcpy((void*)toSlot->address, (void*)fromSlot->address, B_PAGE_SIZE);
     697
     698    slotQueue->PutSlots(fromSlot, toSlot);
     699}
     700
     701
     702status_t
     703LargeMemoryPhysicalPageMapper::GetSlot(bool canWait, PhysicalPageSlot*& slot)
     704{
     705    MutexLocker locker(fLock);
     706
     707    PhysicalPageSlotPool* pool = fNonEmptyPools.Head();
     708    if (pool == NULL) {
     709        if (!canWait)
     710            return B_WOULD_BLOCK;
     711
     712        // allocate new pool
     713        locker.Unlock();
     714        status_t error = fInitialPool->AllocatePool(pool);
     715        if (error != B_OK)
     716            return error;
     717        locker.Lock();
     718
     719        fNonEmptyPools.Add(pool);
     720        pool = fNonEmptyPools.Head();
     721    }
     722
     723    slot = pool->GetSlot();
     724
     725    if (pool->IsEmpty()) {
     726        fNonEmptyPools.Remove(pool);
     727        fEmptyPools.Add(pool);
     728    }
     729
     730    return B_OK;
     731}
     732
     733
     734void
     735LargeMemoryPhysicalPageMapper::PutSlot(PhysicalPageSlot* slot)
     736{
     737    MutexLocker locker(fLock);
     738
     739    PhysicalPageSlotPool* pool = slot->pool;
     740    if (pool->IsEmpty()) {
     741        fEmptyPools.Remove(pool);
     742        fNonEmptyPools.Add(pool);
     743    }
     744
     745    pool->PutSlot(slot);
     746}
     747
     748
     749inline PhysicalPageSlotQueue*
     750LargeMemoryPhysicalPageMapper::GetSlotQueue(int32 cpu, bool user)
     751{
     752    return user ? &fPerCPUData[cpu].user : &fPerCPUData[cpu].kernel;
     753}
     754
     755
     756// #pragma mark - Initialization
     757
     758
     759status_t
     760large_memory_physical_page_ops_init(kernel_args* args,
     761    X86_64LargePhysicalPageMapper::PhysicalPageSlotPool* initialPool,
     762    X86_64PhysicalPageMapper*& _pageMapper,
     763    TranslationMapPhysicalPageMapper*& _kernelPageMapper)
     764{
     765    new(&sPhysicalPageMapper) LargeMemoryPhysicalPageMapper;
     766    sPhysicalPageMapper.Init(args, initialPool, _kernelPageMapper);
     767
     768    _pageMapper = &sPhysicalPageMapper;
     769    return B_OK;
     770}
  • src/system/kernel/arch/x86_64/paging/X86_64PagingStructures.h

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
     5 * Distributed under the terms of the MIT License.
     6 *
     7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     8 * Distributed under the terms of the NewOS License.
     9 */
     10#ifndef KERNEL_ARCH_X86_64_PAGING_X86_64_PAGING_STRUCTURES_H
     11#define KERNEL_ARCH_X86_64_PAGING_X86_64_PAGING_STRUCTURES_H
     12
     13
     14#include <SupportDefs.h>
     15
     16#include <heap.h>
     17#include "paging/paging.h"
     18
     19
     20struct X86_64PagingStructures : DeferredDeletable {
     21    uint64                  pgdir_phys;
     22    vint32                  ref_count;
     23    vint32                  active_on_cpus;
     24        // mask indicating on which CPUs the map is currently used
     25
     26                        X86_64PagingStructures();
     27    virtual                 ~X86_64PagingStructures();
     28
     29    inline  void                AddReference();
     30    inline  void                RemoveReference();
     31
     32    void                    Init(page_directory_pointer_table_entry*
     33                            virtualPDPT, phys_addr_t physicalPDPT, void* pdptHandle,
     34                            page_directory_entry* const* virtualPageDirs,
     35                            const phys_addr_t* physicalPageDirs);
     36
     37    virtual void                Delete();
     38
     39    page_directory_entry* const*        VirtualPageDirs() const
     40                            { return fVirtualPageDirs; }
     41
     42private:
     43    page_directory_pointer_table_entry* fPageDirPointerTable;
     44    void*                   fPageDirPointerTableHandle;
     45    page_directory_entry*           fVirtualPageDirs[4];
     46    phys_addr_t             fPhysicalPageDirs[4];
     47};
     48
     49
     50inline void
     51X86_64PagingStructures::AddReference()
     52{
     53    atomic_add(&ref_count, 1);
     54}
     55
     56
     57inline void
     58X86_64PagingStructures::RemoveReference()
     59{
     60    if (atomic_add(&ref_count, -1) == 1)
     61        Delete();
     62}
     63
     64
     65#endif  // KERNEL_ARCH_X86_64_PAGING_X86_64_PAGING_STRUCTURES_H
  • src/system/kernel/arch/x86_64/arch_commpage.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Copyright 2007, Travis Geiselbrecht. All rights reserved.
     5 * Distributed under the terms of the MIT License.
     6 */
     7
     8
     9#include <string.h>
     10
     11#include <KernelExport.h>
     12
     13#include <commpage.h>
     14#include <cpu.h>
     15#include <elf.h>
     16#include <smp.h>
     17
     18#include <SupportDefs.h>
     19
     20
     21extern "C" void x86_64_sysenter();
     22
     23void (*gX86_64SetSyscallStack)(addr_t stackTop) = NULL;
     24
     25extern "C" void _user_syscall_int(void);
     26extern unsigned int _user_syscall_int_end;
     27extern "C" void _user_syscall_sysenter(void);
     28extern unsigned int _user_syscall_sysenter_end;
     29
     30
     31void
     32x86_64_set_syscall_stack(addr_t stackTop)
     33{
     34    if (gX86_64SetSyscallStack != NULL)
     35        gX86_64SetSyscallStack(stackTop);
     36}
     37
     38
     39static void
     40init_x86_64_syscall_registers(void* dummy, int cpuNum)
     41{
     42    x86_64_write_msr(IA32_MSR_SYSENTER_CS, KERNEL_CODE_SEG);
     43    x86_64_write_msr(IA32_MSR_SYSENTER_ESP, 0);
     44    x86_64_write_msr(IA32_MSR_SYSENTER_EIP, (addr_t)x86_64_sysenter);
     45
     46    gX86_64SetSyscallStack = &x86_64_set_syscall_stack;
     47}
     48
     49
     50static bool
     51all_cpus_have_feature(enum x86_feature_type type, int feature)
     52{
     53    int i;
     54    int cpuCount = smp_get_num_cpus();
     55
     56    for (i = 0; i < cpuCount; i++) {
     57        if (!(gCPU[i].arch.feature[type] & feature))
     58            return false;
     59    }
     60
     61    return true;
     62}
     63
     64
     65status_t
     66arch_commpage_init_post_cpus(void)
     67{
     68    void* syscallCode = (void *)&_user_syscall_int;
     69    void* syscallCodeEnd = &_user_syscall_int_end;
     70
     71    // check syscall
     72    if (all_cpus_have_feature(FEATURE_COMMON, IA32_FEATURE_SEP)
     73        && !(gCPU[0].arch.family == 6 && gCPU[0].arch.model < 3
     74            && gCPU[0].arch.stepping < 3)) {
     75        // Intel sysenter/sysexit
     76        dprintf("initialize_commpage_syscall(): sysenter/sysexit supported\n");
     77
     78        // the code to be used in userland
     79        syscallCode = (void *)&_user_syscall_sysenter;
     80        syscallCodeEnd = &_user_syscall_sysenter_end;
     81
     82        // tell all CPUs to init their sysenter/sysexit related registers
     83        call_all_cpus_sync(&init_x86_64_syscall_registers, NULL);
     84    } else if (all_cpus_have_feature(FEATURE_EXT_AMD,
     85            IA32_FEATURE_AMD_EXT_SYSCALL)) {
     86        // AMD syscall/sysret
     87        dprintf("initialize_commpage_syscall(): syscall/sysret supported "
     88            "-- not yet by Haiku, though");
     89    } else {
     90        // no special syscall support
     91        dprintf("initialize_commpage_syscall(): no special syscall support\n");
     92    }
     93
     94    // fill in the table entry
     95    size_t len = (size_t)((addr_t)syscallCodeEnd - (addr_t)syscallCode);
     96    fill_commpage_entry(COMMPAGE_ENTRY_X86_64_SYSCALL, syscallCode, len);
     97
     98    // add syscall to the commpage image
     99    image_id image = get_commpage_image();
     100    elf_add_memory_image_symbol(image, "commpage_syscall",
     101        ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_64_SYSCALL], len,
     102        B_SYMBOL_TYPE_TEXT);
     103
     104    return B_OK;
     105}
     106
     107
     108status_t
     109arch_commpage_init(void)
     110{
     111    return B_OK;
     112}
  • src/system/kernel/arch/x86_64/arch_int.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de.
     4 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
     5 * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
     6 * Distributed under the terms of the MIT License.
     7 *
     8 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
     9 * Distributed under the terms of the NewOS License.
     10 */
     11
     12
     13#include <cpu.h>
     14#include <int.h>
     15#include <kscheduler.h>
     16#include <ksyscalls.h>
     17#include <smp.h>
     18#include <team.h>
     19#include <thread.h>
     20#include <vm/vm.h>
     21#include <vm/vm_priv.h>
     22
     23#include <arch/cpu.h>
     24#include <arch/int.h>
     25#include <arch/smp.h>
     26#include <arch/user_debugger.h>
     27#include <arch/vm.h>
     28
     29#include <arch/x86_64/apic.h>
     30#include <arch/x86_64/descriptors.h>
     31
     32#include "interrupts.h"
     33#include "irq_routing_table.h"
     34
     35#include <ACPI.h>
     36#include <AutoDeleter.h>
     37#include <safemode.h>
     38#include <string.h>
     39#include <stdio.h>
     40
     41
     42//#define TRACE_ARCH_INT
     43#ifdef TRACE_ARCH_INT
     44#   define TRACE(x) dprintf x
     45#else
     46#   define TRACE(x) ;
     47#endif
     48
     49
     50// Definitions for the PIC 8259 controller
     51// (this is not a complete list, only what we're actually using)
     52
     53#define PIC_MASTER_CONTROL      0x20
     54#define PIC_MASTER_MASK         0x21
     55#define PIC_SLAVE_CONTROL       0xa0
     56#define PIC_SLAVE_MASK          0xa1
     57#define PIC_MASTER_INIT1        PIC_MASTER_CONTROL
     58#define PIC_MASTER_INIT2        PIC_MASTER_MASK
     59#define PIC_MASTER_INIT3        PIC_MASTER_MASK
     60#define PIC_MASTER_INIT4        PIC_MASTER_MASK
     61#define PIC_SLAVE_INIT1         PIC_SLAVE_CONTROL
     62#define PIC_SLAVE_INIT2         PIC_SLAVE_MASK
     63#define PIC_SLAVE_INIT3         PIC_SLAVE_MASK
     64#define PIC_SLAVE_INIT4         PIC_SLAVE_MASK
     65
     66// the edge/level trigger control registers
     67#define PIC_MASTER_TRIGGER_MODE 0x4d0
     68#define PIC_SLAVE_TRIGGER_MODE  0x4d1
     69
     70#define PIC_INIT1               0x10
     71#define PIC_INIT1_SEND_INIT4    0x01
     72#define PIC_INIT3_IR2_IS_SLAVE  0x04
     73#define PIC_INIT3_SLAVE_ID2     0x02
     74#define PIC_INIT4_x86_MODE      0x01
     75
     76#define PIC_CONTROL3            0x08
     77#define PIC_CONTROL3_READ_ISR   0x03
     78#define PIC_CONTROL3_READ_IRR   0x02
     79
     80#define PIC_NON_SPECIFIC_EOI    0x20
     81
     82#define PIC_SLAVE_INT_BASE      8
     83#define PIC_NUM_INTS            0x0f
     84
     85
     86// Definitions for a 82093AA IO APIC controller
     87#define IO_APIC_IDENTIFICATION              0x00
     88#define IO_APIC_VERSION                     0x01
     89#define IO_APIC_ARBITRATION                 0x02
     90#define IO_APIC_REDIRECTION_TABLE           0x10 // entry = base + 2 * index
     91
     92// Fields for the version register
     93#define IO_APIC_VERSION_SHIFT               0
     94#define IO_APIC_VERSION_MASK                0xff
     95#define IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT 16
     96#define IO_APIC_MAX_REDIRECTION_ENTRY_MASK  0xff
     97
     98// Fields of each redirection table entry
     99#define IO_APIC_DESTINATION_FIELD_SHIFT     56
     100#define IO_APIC_DESTINATION_FIELD_MASK      0x0f
     101#define IO_APIC_INTERRUPT_MASK_SHIFT        16
     102#define IO_APIC_INTERRUPT_MASKED            1
     103#define IO_APIC_INTERRUPT_UNMASKED          0
     104#define IO_APIC_TRIGGER_MODE_SHIFT          15
     105#define IO_APIC_TRIGGER_MODE_EDGE           0
     106#define IO_APIC_TRIGGER_MODE_LEVEL          1
     107#define IO_APIC_REMOTE_IRR_SHIFT            14
     108#define IO_APIC_PIN_POLARITY_SHIFT          13
     109#define IO_APIC_PIN_POLARITY_HIGH_ACTIVE    0
     110#define IO_APIC_PIN_POLARITY_LOW_ACTIVE     1
     111#define IO_APIC_DELIVERY_STATUS_SHIFT       12
     112#define IO_APIC_DELIVERY_STATUS_IDLE        0
     113#define IO_APIC_DELIVERY_STATUS_PENDING     1
     114#define IO_APIC_DESTINATION_MODE_SHIFT      11
     115#define IO_APIC_DESTINATION_MODE_PHYSICAL   0
     116#define IO_APIC_DESTINATION_MODE_LOGICAL    1
     117#define IO_APIC_DELIVERY_MODE_SHIFT         8
     118#define IO_APIC_DELIVERY_MODE_MASK          0x07
     119#define IO_APIC_DELIVERY_MODE_FIXED         0
     120#define IO_APIC_DELIVERY_MODE_LOWEST_PRIO   1
     121#define IO_APIC_DELIVERY_MODE_SMI           2
     122#define IO_APIC_DELIVERY_MODE_NMI           4
     123#define IO_APIC_DELIVERY_MODE_INIT          5
     124#define IO_APIC_DELIVERY_MODE_EXT_INT       7
     125#define IO_APIC_INTERRUPT_VECTOR_SHIFT      0
     126#define IO_APIC_INTERRUPT_VECTOR_MASK       0xff
     127
     128typedef struct ioapic_s {
     129    volatile uint32 io_register_select;
     130    uint32          reserved[3];
     131    volatile uint32 io_window_register;
     132} ioapic;
     133
     134static ioapic *sIOAPIC = NULL;
     135static uint32 sIOAPICMaxRedirectionEntry = 23;
     136
     137static uint32 sIRQToIOAPICPin[256];
     138
     139typedef struct interrupt_controller_s {
     140    const char *name;
     141    void    (*enable_io_interrupt)(int32 num);
     142    void    (*disable_io_interrupt)(int32 num);
     143    void    (*configure_io_interrupt)(int32 num, uint32 config);
     144    bool    (*is_spurious_interrupt)(int32 num);
     145    bool    (*end_of_interrupt)(int32 num);
     146} interrupt_controller;
     147
     148static const interrupt_controller *sCurrentPIC = NULL;
     149
     150static const char *kInterruptNames[] = {
     151    /*  0 */ "Divide Error Exception",
     152    /*  1 */ "Debug Exception",
     153    /*  2 */ "NMI Interrupt",
     154    /*  3 */ "Breakpoint Exception",
     155    /*  4 */ "Overflow Exception",
     156    /*  5 */ "BOUND Range Exceeded Exception",
     157    /*  6 */ "Invalid Opcode Exception",
     158    /*  7 */ "Device Not Available Exception",
     159    /*  8 */ "Double Fault Exception",
     160    /*  9 */ "Coprocessor Segment Overrun",
     161    /* 10 */ "Invalid TSS Exception",
     162    /* 11 */ "Segment Not Present",
     163    /* 12 */ "Stack Fault Exception",
     164    /* 13 */ "General Protection Exception",
     165    /* 14 */ "Page-Fault Exception",
     166    /* 15 */ "-",
     167    /* 16 */ "x87 FPU Floating-Point Error",
     168    /* 17 */ "Alignment Check Exception",
     169    /* 18 */ "Machine-Check Exception",
     170    /* 19 */ "SIMD Floating-Point Exception",
     171};
     172static const int kInterruptNameCount = 20;
     173
     174#define MAX_ARGS 16
     175
     176typedef struct {
     177    uint32 a, b;
     178} desc_table;
     179static desc_table* sIDTs[B_MAX_CPU_COUNT];
     180
     181static uint32 sLevelTriggeredInterrupts = 0;
     182    // binary mask: 1 level, 0 edge
     183
     184// table with functions handling respective interrupts
     185typedef void interrupt_handler_function(struct iframe* frame);
     186#define INTERRUPT_HANDLER_TABLE_SIZE 256
     187interrupt_handler_function* gInterruptHandlerTable[
     188    INTERRUPT_HANDLER_TABLE_SIZE];
     189
     190
     191/*! Returns the virtual IDT address for CPU \a cpu. */
     192void*
     193x86_64_get_idt(int32 cpu)
     194{
     195    return sIDTs[cpu];
     196}
     197
     198/*! Initializes a descriptor in an IDT.
     199*/
     200static void
     201set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
     202{
     203    unsigned int gate1; // first byte of gate desc
     204    unsigned int gate2; // second byte of gate desc
     205
     206    gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr);
     207    gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8);
     208
     209    gate_addr->a = gate1;
     210    gate_addr->b = gate2;
     211}
     212
     213
     214/*! Initializes the descriptor for interrupt vector \a n in the IDT of the
     215    specified CPU to an interrupt-gate descriptor with the given procedure
     216    address.
     217    For CPUs other than the boot CPU it must not be called before
     218    arch_int_init_post_vm().
     219*/
     220static void
     221set_interrupt_gate(int32 cpu, int n, void (*addr)())
     222{
     223    set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL);
     224}
     225
     226
     227/*! Initializes the descriptor for interrupt vector \a n in the IDT of the
     228    specified CPU to an trap-gate descriptor with the given procedure address.
     229    For CPUs other than the boot CPU it must not be called before
     230    arch_int_init_post_vm().
     231*/
     232static void
     233set_trap_gate(int32 cpu, int n, void (*addr)())
     234{
     235    set_gate(&sIDTs[cpu][n], (addr_t)addr, 15, DPL_USER);
     236}
     237
     238
     239/*! Initializes the descriptor for interrupt vector \a n in the IDT of CPU
     240    \a cpu to a task-gate descripter referring to the TSS segment identified
     241    by TSS segment selector \a segment.
     242    For CPUs other than the boot CPU it must not be called before
     243    arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
     244*/
     245void
     246x86_64_set_task_gate(int32 cpu, int32 n, int32 segment)
     247{
     248    sIDTs[cpu][n].a = (segment << 16);
     249    sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
     250}
     251
     252
     253// #pragma mark - PIC
     254
     255
     256/*! Tests if the interrupt in-service register of the responsible
     257    PIC is set for interrupts 7 and 15, and if that's not the case,
     258    it must assume it's a spurious interrupt.
     259*/
     260static bool
     261pic_is_spurious_interrupt(int32 num)
     262{
     263    if (num != 7)
     264        return false;
     265
     266    // Note, detecting spurious interrupts on line 15 obviously doesn't
     267    // work correctly - and since those are extremely rare, anyway, we
     268    // just ignore them
     269
     270    out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, PIC_MASTER_CONTROL);
     271    int32 isr = in8(PIC_MASTER_CONTROL);
     272    out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, PIC_MASTER_CONTROL);
     273
     274    return (isr & 0x80) == 0;
     275}
     276
     277
     278/*! Sends a non-specified EOI (end of interrupt) notice to the PIC in
     279    question (or both of them).
     280    This clears the PIC interrupt in-service bit.
     281*/
     282static bool
     283pic_end_of_interrupt(int32 num)
     284{
     285    if (num < 0 || num > PIC_NUM_INTS)
     286        return false;
     287
     288    // PIC 8259 controlled interrupt
     289    if (num >= PIC_SLAVE_INT_BASE)
     290        out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL);
     291
     292    // we always need to acknowledge the master PIC
     293    out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL);
     294    return true;
     295}
     296
     297
     298static void
     299pic_enable_io_interrupt(int32 num)
     300{
     301    // interrupt is specified "normalized"
     302    if (num < 0 || num > PIC_NUM_INTS)
     303        return;
     304
     305    // enable PIC 8259 controlled interrupt
     306
     307    TRACE(("pic_enable_io_interrupt: irq %ld\n", num));
     308
     309    if (num < PIC_SLAVE_INT_BASE)
     310        out8(in8(PIC_MASTER_MASK) & ~(1 << num), PIC_MASTER_MASK);
     311    else
     312        out8(in8(PIC_SLAVE_MASK) & ~(1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK);
     313}
     314
     315
     316static void
     317pic_disable_io_interrupt(int32 num)
     318{
     319    // interrupt is specified "normalized"
     320    // never disable slave pic line IRQ 2
     321    if (num < 0 || num > PIC_NUM_INTS || num == 2)
     322        return;
     323
     324    // disable PIC 8259 controlled interrupt
     325
     326    TRACE(("pic_disable_io_interrupt: irq %ld\n", num));
     327
     328    if (num < PIC_SLAVE_INT_BASE)
     329        out8(in8(PIC_MASTER_MASK) | (1 << num), PIC_MASTER_MASK);
     330    else
     331        out8(in8(PIC_SLAVE_MASK) | (1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK);
     332}
     333
     334
     335static void
     336pic_configure_io_interrupt(int32 num, uint32 config)
     337{
     338    uint8 value;
     339    int32 localBit;
     340    if (num < 0 || num > PIC_NUM_INTS || num == 2)
     341        return;
     342
     343    TRACE(("pic_configure_io_interrupt: irq %ld; config 0x%08lx\n", num, config));
     344
     345    if (num < PIC_SLAVE_INT_BASE) {
     346        value = in8(PIC_MASTER_TRIGGER_MODE);
     347        localBit = num;
     348    } else {
     349        value = in8(PIC_SLAVE_TRIGGER_MODE);
     350        localBit = num - PIC_SLAVE_INT_BASE;
     351    }
     352
     353    if (config & B_LEVEL_TRIGGERED)
     354        value |= 1 << localBit;
     355    else
     356        value &= ~(1 << localBit);
     357
     358    if (num < PIC_SLAVE_INT_BASE)
     359        out8(value, PIC_MASTER_TRIGGER_MODE);
     360    else
     361        out8(value, PIC_SLAVE_TRIGGER_MODE);
     362
     363    sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE)
     364        | (in8(PIC_SLAVE_TRIGGER_MODE) << 8);
     365}
     366
     367
     368static void
     369pic_init(void)
     370{
     371    static interrupt_controller picController = {
     372        "8259 PIC",
     373        &pic_enable_io_interrupt,
     374        &pic_disable_io_interrupt,
     375        &pic_configure_io_interrupt,
     376        &pic_is_spurious_interrupt,
     377        &pic_end_of_interrupt
     378    };
     379
     380    // Start initialization sequence for the master and slave PICs
     381    out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1);
     382    out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1);
     383
     384    // Set start of interrupts to 0x20 for master, 0x28 for slave
     385    out8(ARCH_INTERRUPT_BASE, PIC_MASTER_INIT2);
     386    out8(ARCH_INTERRUPT_BASE + PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2);
     387
     388    // Specify cascading through interrupt 2
     389    out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3);
     390    out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3);
     391
     392    // Set both to operate in 8086 mode
     393    out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4);
     394    out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4);
     395
     396    out8(0xfb, PIC_MASTER_MASK);    // Mask off all interrupts (except slave pic line IRQ 2).
     397    out8(0xff, PIC_SLAVE_MASK);     // Mask off interrupts on the slave.
     398
     399    // determine which interrupts are level or edge triggered
     400
     401#if 0
     402    // should set everything possible to level triggered
     403    out8(0xf8, PIC_MASTER_TRIGGER_MODE);
     404    out8(0xde, PIC_SLAVE_TRIGGER_MODE);
     405#endif
     406
     407    sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE)
     408        | (in8(PIC_SLAVE_TRIGGER_MODE) << 8);
     409
     410    TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts));
     411
     412    // make the pic controller the current one
     413    sCurrentPIC = &picController;
     414}
     415
     416
     417// #pragma mark - I/O APIC
     418
     419
     420static inline uint32
     421ioapic_read_32(uint8 registerSelect)
     422{
     423    sIOAPIC->io_register_select = registerSelect;
     424    return sIOAPIC->io_window_register;
     425}
     426
     427
     428static inline void
     429ioapic_write_32(uint8 registerSelect, uint32 value)
     430{
     431    sIOAPIC->io_register_select = registerSelect;
     432    sIOAPIC->io_window_register = value;
     433}
     434
     435
     436static inline uint64
     437ioapic_read_64(uint8 registerSelect)
     438{
     439    sIOAPIC->io_register_select = registerSelect + 1;
     440    uint64 result = sIOAPIC->io_window_register;
     441    result <<= 32;
     442    sIOAPIC->io_register_select = registerSelect;
     443    result |= sIOAPIC->io_window_register;
     444    return result;
     445}
     446
     447
     448static inline void
     449ioapic_write_64(uint8 registerSelect, uint64 value)
     450{
     451    sIOAPIC->io_register_select = registerSelect;
     452    sIOAPIC->io_window_register = (uint32)value;
     453    sIOAPIC->io_register_select = registerSelect + 1;
     454    sIOAPIC->io_window_register = (uint32)(value >> 32);
     455}
     456
     457
     458static bool
     459ioapic_is_spurious_interrupt(int32 num)
     460{
     461    // the spurious interrupt vector is initialized to the max value in smp
     462    return num == 0xff - ARCH_INTERRUPT_BASE;
     463}
     464
     465
     466static bool
     467ioapic_end_of_interrupt(int32 num)
     468{
     469    apic_end_of_interrupt();
     470    return true;
     471}
     472
     473
     474static void
     475ioapic_enable_io_interrupt(int32 num)
     476{
     477    int32 pin = sIRQToIOAPICPin[num];
     478    if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
     479        return;
     480
     481    TRACE(("ioapic_enable_io_interrupt: IRQ %ld -> pin %ld\n", num, pin));
     482
     483    uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2);
     484    entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
     485    entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
     486    ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
     487}
     488
     489
     490static void
     491ioapic_disable_io_interrupt(int32 num)
     492{
     493    int32 pin = sIRQToIOAPICPin[num];
     494    if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
     495        return;
     496
     497    TRACE(("ioapic_disable_io_interrupt: IRQ %ld -> pin %ld\n", num, pin));
     498
     499    uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2);
     500    entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
     501    entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
     502    ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
     503}
     504
     505
     506static void
     507ioapic_configure_io_interrupt(int32 num, uint32 config)
     508{
     509    int32 pin = sIRQToIOAPICPin[num];
     510    if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
     511        return;
     512
     513    TRACE(("ioapic_configure_io_interrupt: IRQ %ld -> pin %ld; config 0x%08lx\n",
     514        num, pin, config));
     515
     516    uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2);
     517    entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT)
     518        | (1 << IO_APIC_PIN_POLARITY_SHIFT)
     519        | (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT));
     520
     521    if (config & B_LEVEL_TRIGGERED) {
     522        entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT);
     523        sLevelTriggeredInterrupts |= (1 << num);
     524    } else {
     525        entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT);
     526        sLevelTriggeredInterrupts &= ~(1 << num);
     527    }
     528
     529    if (config & B_LOW_ACTIVE_POLARITY)
     530        entry |= (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT);
     531    else
     532        entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT);
     533
     534    entry |= (num + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT;
     535    ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
     536}
     537
     538
     539static void
     540ioapic_map(kernel_args* args)
     541{
     542    if (args->arch_args.apic == NULL) {
     543        dprintf("no local apic available\n");
     544        return;
     545    }
     546
     547    if (args->arch_args.ioapic == NULL) {
     548        dprintf("no ioapic available, not using ioapics for interrupt routing\n");
     549        return;
     550    }
     551
     552    // map in the ioapic
     553    sIOAPIC = (ioapic *)((void*)args->arch_args.ioapic);
     554    if (vm_map_physical_memory(B_SYSTEM_TEAM, "ioapic", (void**)&sIOAPIC,
     555            B_EXACT_ADDRESS, B_PAGE_SIZE,
     556            B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
     557            args->arch_args.ioapic_phys, true) < 0) {
     558        panic("mapping the ioapic failed");
     559        return;
     560    }
     561}
     562
     563
     564static void
     565ioapic_init(kernel_args* args)
     566{
     567    static const interrupt_controller ioapicController = {
     568        "82093AA IOAPIC",
     569        &ioapic_enable_io_interrupt,
     570        &ioapic_disable_io_interrupt,
     571        &ioapic_configure_io_interrupt,
     572        &ioapic_is_spurious_interrupt,
     573        &ioapic_end_of_interrupt
     574    };
     575
     576    if (sIOAPIC == NULL)
     577        return;
     578
     579    if (!get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, true)) {
     580        dprintf("ioapic explicitly disabled, not using ioapics for interrupt "
     581            "routing\n");
     582        return;
     583    }
     584
     585    uint32 version = ioapic_read_32(IO_APIC_VERSION);
     586    if (version == 0xffffffff) {
     587        dprintf("ioapic seems inaccessible, not using it\n");
     588        return;
     589    }
     590
     591// disable io apic for now
     592return;
     593
     594    // load acpi module
     595    status_t status;
     596    acpi_module_info* acpiModule;
     597    status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
     598    if (status != B_OK) {
     599        dprintf("acpi module not available, not configuring ioapic\n");
     600        return;
     601    }
     602    BPrivate::CObjectDeleter<const char, status_t>
     603        acpiModulePutter(B_ACPI_MODULE_NAME, put_module);
     604
     605    // load pci module
     606    pci_module_info* pciModule;
     607    status = get_module(B_PCI_MODULE_NAME, (module_info**)&pciModule);
     608    if (status != B_OK) {
     609        dprintf("could not load pci module, not configuring ioapic\n");
     610        return;
     611    }
     612    CObjectDeleter<const char, status_t> pciModulePutter(B_PCI_MODULE_NAME,
     613        put_module);
     614
     615    // TODO: here ACPI needs to be used to properly set up the PCI IRQ
     616    // routing.
     617
     618    IRQRoutingTable table;
     619    status = read_irq_routing_table(pciModule, acpiModule, &table);
     620    if (status != B_OK) {
     621        dprintf("reading IRQ routing table failed, no ioapic.\n");
     622        return;
     623    }
     624
     625    sLevelTriggeredInterrupts = 0;
     626    sIOAPICMaxRedirectionEntry
     627        = ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT)
     628            & IO_APIC_MAX_REDIRECTION_ENTRY_MASK);
     629
     630    // use the boot CPU as the target for all interrupts
     631    uint64 targetAPIC = args->arch_args.cpu_apic_id[0];
     632
     633    // program the interrupt vectors of the ioapic
     634    for (uint32 i = 0; i <= sIOAPICMaxRedirectionEntry; i++) {
     635        // initialize everything to deliver to the boot CPU in physical mode
     636        // and masked until explicitly enabled through enable_io_interrupt()
     637        uint64 entry = (targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT)
     638            | (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT)
     639            | (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT)
     640            | ((i + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT);
     641
     642        if (i == 0) {
     643            // make redirection entry 0 into an external interrupt
     644            entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
     645                | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
     646                | (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT);
     647        } else if (i < 16) {
     648            // make 1-15 ISA interrupts
     649            entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
     650                | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
     651                | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
     652        } else {
     653            // and the rest are PCI interrupts
     654            entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT)
     655                | (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
     656                | (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
     657            sLevelTriggeredInterrupts |= (1 << i);
     658        }
     659
     660        ioapic_write_64(IO_APIC_REDIRECTION_TABLE + 2 * i, entry);
     661    }
     662
     663    // setup default 1:1 mapping
     664    for (uint32 i = 0; i < 256; i++)
     665        sIRQToIOAPICPin[i] = i;
     666
     667    // configure apic interrupts assume 1:1 mapping
     668    for (int i = 0; i < table.Count(); i++) {
     669        irq_routing_entry& entry = table.ElementAt(i);
     670        irq_descriptor irqDescriptor;
     671        read_current_irq(acpiModule, entry.source, &irqDescriptor);
     672        uint32 config = 0;
     673        config |= irqDescriptor.polarity;
     674        config |= irqDescriptor.interrupt_mode;
     675       
     676        int32 num = -1;
     677        for (int a = 0; a < 16; a++) {
     678            if (irqDescriptor.irq >> i & 0x01) {
     679                num = a;
     680                break;
     681            }
     682        }
     683        ioapic_configure_io_interrupt(num, config);
     684    }
     685
     686    // prefer the ioapic over the normal pic
     687    dprintf("using ioapic for interrupt routing\n");
     688    sCurrentPIC = &ioapicController;
     689}
     690
     691
     692// #pragma mark -
     693
     694
     695void
     696arch_int_enable_io_interrupt(int irq)
     697{
     698    sCurrentPIC->enable_io_interrupt(irq);
     699}
     700
     701
     702void
     703arch_int_disable_io_interrupt(int irq)
     704{
     705    sCurrentPIC->disable_io_interrupt(irq);
     706}
     707
     708
     709void
     710arch_int_configure_io_interrupt(int irq, uint32 config)
     711{
     712    sCurrentPIC->configure_io_interrupt(irq, config);
     713}
     714
     715
     716#undef arch_int_enable_interrupts
     717#undef arch_int_disable_interrupts
     718#undef arch_int_restore_interrupts
     719#undef arch_int_are_interrupts_enabled
     720
     721
     722void
     723arch_int_enable_interrupts(void)
     724{
     725    arch_int_enable_interrupts_inline();
     726}
     727
     728
     729int
     730arch_int_disable_interrupts(void)
     731{
     732    return arch_int_disable_interrupts_inline();
     733}
     734
     735
     736void
     737arch_int_restore_interrupts(int oldState)
     738{
     739    arch_int_restore_interrupts_inline(oldState);
     740}
     741
     742
     743bool
     744arch_int_are_interrupts_enabled(void)
     745{
     746    return arch_int_are_interrupts_enabled_inline();
     747}
     748
     749
     750static const char *
     751exception_name(int number, char *buffer, int32 bufferSize)
     752{
     753    if (number >= 0 && number < kInterruptNameCount)
     754        return kInterruptNames[number];
     755
     756    snprintf(buffer, bufferSize, "exception %d", number);
     757    return buffer;
     758}
     759
     760
     761static void
     762invalid_exception(struct iframe* frame)
     763{
     764    struct thread* thread = thread_get_current_thread();
     765    char name[32];
     766    panic("unhandled trap 0x%llx (%s) at ip 0x%llx, thread %ld!\n",
     767        frame->vector, exception_name(frame->vector, name, sizeof(name)),
     768        frame->rip, thread ? thread->id : -1);
     769}
     770
     771
     772static void
     773fatal_exception(struct iframe *frame)
     774{
     775    char name[32];
     776    panic("Fatal exception \"%s\" occurred! Error code: 0x%llx\n",
     777        exception_name(frame->vector, name, sizeof(name)), frame->error_code);
     778}
     779
     780
     781static void
     782unexpected_exception(struct iframe* frame)
     783{
     784    debug_exception_type type;
     785    int signal;
     786
     787    switch (frame->vector) {
     788        case 0:     // Divide Error Exception (#DE)
     789            type = B_DIVIDE_ERROR;
     790            signal = SIGFPE;
     791            break;
     792
     793        case 4:     // Overflow Exception (#OF)
     794            type = B_OVERFLOW_EXCEPTION;
     795            signal = SIGTRAP;
     796            break;
     797
     798        case 5:     // BOUND Range Exceeded Exception (#BR)
     799            type = B_BOUNDS_CHECK_EXCEPTION;
     800            signal = SIGTRAP;
     801            break;
     802
     803        case 6:     // Invalid Opcode Exception (#UD)
     804            type = B_INVALID_OPCODE_EXCEPTION;
     805            signal = SIGILL;
     806            break;
     807
     808        case 13:    // General Protection Exception (#GP)
     809            type = B_GENERAL_PROTECTION_FAULT;
     810            signal = SIGILL;
     811            break;
     812
     813        case 16:    // x87 FPU Floating-Point Error (#MF)
     814            type = B_FLOATING_POINT_EXCEPTION;
     815            signal = SIGFPE;
     816            break;
     817
     818        case 17:    // Alignment Check Exception (#AC)
     819            type = B_ALIGNMENT_EXCEPTION;
     820            signal = SIGTRAP;
     821            break;
     822
     823        case 19:    // SIMD Floating-Point Exception (#XF)
     824            type = B_FLOATING_POINT_EXCEPTION;
     825            signal = SIGFPE;
     826            break;
     827
     828        default:
     829            invalid_exception(frame);
     830            return;
     831    }
     832
     833    if (IFRAME_IS_USER(frame)) {
     834        struct sigaction action;
     835        struct thread* thread = thread_get_current_thread();
     836
     837        enable_interrupts();
     838
     839        // If the thread has a signal handler for the signal, we simply send it
     840        // the signal. Otherwise we notify the user debugger first.
     841        if (sigaction(signal, NULL, &action) == 0
     842            && action.sa_handler != SIG_DFL
     843            && action.sa_handler != SIG_IGN) {
     844            send_signal(thread->id, signal);
     845        } else if (user_debug_exception_occurred(type, signal))
     846            send_signal(team_get_current_team_id(), signal);
     847    } else {
     848        char name[32];
     849        panic("Unexpected exception \"%s\" occurred in kernel mode! "
     850            "Error code: 0x%llx\n",
     851            exception_name(frame->vector, name, sizeof(name)),
     852            frame->error_code);
     853    }
     854}
     855
     856
     857void
     858x86_64_double_fault_exception(struct iframe* frame)
     859{
     860    int cpu = x86_64_double_fault_get_cpu();
     861
     862    // The double fault iframe contains no useful information (as
     863    // per Intel's architecture spec). Thus we simply save the
     864    // information from the (unhandlable) exception which caused the
     865    // double in our iframe. This will result even in useful stack
     866    // traces. Only problem is that we trust that at least the
     867    // TSS is still accessible.
     868    struct tss *tss = &gCPU[cpu].arch.tss;
     869
     870    frame->cs = tss->cs;
     871    frame->es = tss->es;
     872    frame->ds = tss->ds;
     873    frame->fs = tss->fs;
     874    frame->gs = tss->gs;
     875    frame->rip = tss->rip;
     876    frame->rbp = tss->rbp;
     877    frame->rsp = tss->rsp;
     878    frame->rax = tss->rax;
     879    frame->rbx = tss->rbx;
     880    frame->rcx = tss->rcx;
     881    frame->rdx = tss->rdx;
     882    frame->rsi = tss->rsi;
     883    frame->rdi = tss->rdi;
     884    frame->flags = tss->eflags;
     885
     886    // Use a special handler for page faults which avoids the triple fault
     887    // pitfalls.
     888    set_interrupt_gate(cpu, 14, &trap14_double_fault);
     889
     890    debug_double_fault(cpu);
     891}
     892
     893
     894/*! Initializes the descriptor for interrupt vector \a n in the IDT of CPU
     895    \a cpu to a task-gate descripter referring to the TSS segment identified
     896    by TSS segment selector \a segment.
     897    For CPUs other than the boot CPU it must not be called before
     898    arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
     899*/
     900void
     901x86_set_task_gate(int32 cpu, int32 n, int32 segment)
     902{
     903    sIDTs[cpu][n].a = (segment << 16);
     904    sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
     905}
     906
     907
     908void
     909x86_64_page_fault_exception_double_fault(struct iframe* frame)
     910{
     911    uint64 cr2;
     912    asm("mov %%cr2, %0" : "=r" (cr2));
     913
     914    // Only if this CPU has a fault handler, we're allowed to be here.
     915    cpu_ent& cpu = gCPU[x86_64_double_fault_get_cpu()];
     916    addr_t faultHandler = cpu.fault_handler;
     917    if (faultHandler != 0) {
     918        debug_set_page_fault_info(cr2, frame->rip,
     919            (frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
     920        frame->rip = faultHandler;
     921        frame->rbp = cpu.fault_handler_stack_pointer;
     922        return;
     923    }
     924
     925    // No fault handler. This is bad. Since we originally came from a double
     926    // fault, we don't try to reenter the kernel debugger. Instead we just
     927    // print the info we've got and enter an infinite loop.
     928    kprintf("Page fault in double fault debugger without fault handler! "
     929        "Touching address %p from rip %p. Entering infinite loop...\n",
     930        (void*)cr2, (void*)frame->rip);
     931
     932    while (true);
     933}
     934
     935
     936static void
     937page_fault_exception(struct iframe* frame)
     938{
     939    struct thread *thread = thread_get_current_thread();
     940    uint64 cr2;
     941    addr_t newip;
     942
     943    asm("mov %%cr2, %0" : "=r" (cr2));
     944
     945    if (debug_debugger_running()) {
     946        // If this CPU or this thread has a fault handler, we're allowed to be
     947        // here.
     948        if (thread != NULL) {
     949            cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
     950            if (cpu->fault_handler != 0) {
     951                debug_set_page_fault_info(cr2, frame->rip,
     952                    (frame->error_code & 0x2) != 0
     953                        ? DEBUG_PAGE_FAULT_WRITE : 0);
     954                frame->rip = cpu->fault_handler;
     955                frame->rbp = cpu->fault_handler_stack_pointer;
     956                return;
     957            }
     958
     959            if (thread->fault_handler != 0) {
     960                kprintf("ERROR: thread::fault_handler used in kernel "
     961                    "debugger!\n");
     962                debug_set_page_fault_info(cr2, frame->rip,
     963                    (frame->error_code & 0x2) != 0
     964                        ? DEBUG_PAGE_FAULT_WRITE : 0);
     965                frame->rip = thread->fault_handler;
     966                return;
     967            }
     968        }
     969
     970        // otherwise, not really
     971        panic("page fault in debugger without fault handler! Touching "
     972            "address %p from rip %p\n", (void *)cr2, (void *)frame->rip);
     973        return;
     974    } else if ((frame->flags & 0x200) == 0) {
     975        // interrupts disabled
     976
     977        // If a page fault handler is installed, we're allowed to be here.
     978        // TODO: Now we are generally allowing user_memcpy() with interrupts
     979        // disabled, which in most cases is a bug. We should add some thread
     980        // flag allowing to explicitly indicate that this handling is desired.
     981        if (thread && thread->fault_handler != 0) {
     982            if (frame->rip != thread->fault_handler) {
     983                frame->rip = thread->fault_handler;
     984                return;
     985            }
     986
     987            // The fault happened at the fault handler address. This is a
     988            // certain infinite loop.
     989            panic("page fault, interrupts disabled, fault handler loop. "
     990                "Touching address %p from rip %p\n", (void*)cr2,
     991                (void*)frame->rip);
     992        }
     993
     994        // If we are not running the kernel startup the page fault was not
     995        // allowed to happen and we must panic.
     996        panic("page fault, but interrupts were disabled. Touching address "
     997            "%p from rip %p\n", (void *)cr2, (void *)frame->rip);
     998        return;
     999    } else if (thread != NULL && thread->page_faults_allowed < 1) {
     1000        panic("page fault not allowed at this place. Touching address "
     1001            "%p from rip %p\n", (void *)cr2, (void *)frame->rip);
     1002        return;
     1003    }
     1004
     1005    enable_interrupts();
     1006
     1007    vm_page_fault(cr2, frame->rip,
     1008        (frame->error_code & 0x2) != 0, // write access
     1009        (frame->error_code & 0x4) != 0, // userland
     1010        &newip);
     1011    if (newip != 0) {
     1012        // the page fault handler wants us to modify the iframe to set the
     1013        // IP the cpu will return to to be this ip
     1014        frame->rip = newip;
     1015    }
     1016}
     1017
     1018
     1019static void
     1020hardware_interrupt(struct iframe* frame)
     1021{
     1022    int32 vector = frame->vector - ARCH_INTERRUPT_BASE;
     1023    bool levelTriggered = false;
     1024    struct thread* thread = thread_get_current_thread();
     1025
     1026    if (sCurrentPIC->is_spurious_interrupt(vector)) {
     1027        TRACE(("got spurious interrupt at vector %ld\n", vector));
     1028        return;
     1029    }
     1030
     1031    if (vector < 32)
     1032        levelTriggered = (sLevelTriggeredInterrupts & (1 << vector)) != 0;
     1033
     1034    if (!levelTriggered) {
     1035        // if it's not handled by the current pic then it's an apic generated
     1036        // interrupt like local interrupts, msi or ipi.
     1037        if (!sCurrentPIC->end_of_interrupt(vector))
     1038            apic_end_of_interrupt();
     1039    }
     1040
     1041    int_io_interrupt_handler(vector, levelTriggered);
     1042
     1043    if (levelTriggered) {
     1044        if (!sCurrentPIC->end_of_interrupt(vector))
     1045            apic_end_of_interrupt();
     1046    }
     1047
     1048    cpu_status state = disable_interrupts();
     1049    if (thread->cpu->invoke_scheduler) {
     1050        GRAB_THREAD_LOCK();
     1051        scheduler_reschedule();
     1052        RELEASE_THREAD_LOCK();
     1053        restore_interrupts(state);
     1054    } else if (thread->post_interrupt_callback != NULL) {
     1055        restore_interrupts(state);
     1056        void (*callback)(void*) = thread->post_interrupt_callback;
     1057        void* data = thread->post_interrupt_data;
     1058
     1059        thread->post_interrupt_callback = NULL;
     1060        thread->post_interrupt_data = NULL;
     1061
     1062        callback(data);
     1063    }
     1064}
     1065
     1066
     1067status_t
     1068arch_int_init(struct kernel_args *args)
     1069{
     1070    int i;
     1071    interrupt_handler_function** table;
     1072
     1073    // set the global sIDT variable
     1074    sIDTs[0] = (desc_table *)args->arch_args.vir_idt;
     1075
     1076    // setup the standard programmable interrupt controller
     1077    pic_init();
     1078
     1079    set_interrupt_gate(0, 0, &trap0);
     1080    set_interrupt_gate(0, 1, &trap1);
     1081    set_interrupt_gate(0, 2, &trap2);
     1082    set_trap_gate(0, 3, &trap3);
     1083    set_interrupt_gate(0, 4, &trap4);
     1084    set_interrupt_gate(0, 5, &trap5);
     1085    set_interrupt_gate(0, 6, &trap6);
     1086    set_interrupt_gate(0, 7, &trap7);
     1087    // trap8 (double fault) is set in arch_cpu.c
     1088    set_interrupt_gate(0, 9, &trap9);
     1089    set_interrupt_gate(0, 10, &trap10);
     1090    set_interrupt_gate(0, 11, &trap11);
     1091    set_interrupt_gate(0, 12, &trap12);
     1092    set_interrupt_gate(0, 13, &trap13);
     1093    set_interrupt_gate(0, 14, &trap14);
     1094//  set_interrupt_gate(0, 15, &trap15);
     1095    set_interrupt_gate(0, 16, &trap16);
     1096    set_interrupt_gate(0, 17, &trap17);
     1097    set_interrupt_gate(0, 18, &trap18);
     1098    set_interrupt_gate(0, 19, &trap19);
     1099
     1100    // legacy or ioapic interrupts
     1101    set_interrupt_gate(0, 32, &trap32);
     1102    set_interrupt_gate(0, 33, &trap33);
     1103    set_interrupt_gate(0, 34, &trap34);
     1104    set_interrupt_gate(0, 35, &trap35);
     1105    set_interrupt_gate(0, 36, &trap36);
     1106    set_interrupt_gate(0, 37, &trap37);
     1107    set_interrupt_gate(0, 38, &trap38);
     1108    set_interrupt_gate(0, 39, &trap39);
     1109    set_interrupt_gate(0, 40, &trap40);
     1110    set_interrupt_gate(0, 41, &trap41);
     1111    set_interrupt_gate(0, 42, &trap42);
     1112    set_interrupt_gate(0, 43, &trap43);
     1113    set_interrupt_gate(0, 44, &trap44);
     1114    set_interrupt_gate(0, 45, &trap45);
     1115    set_interrupt_gate(0, 46, &trap46);
     1116    set_interrupt_gate(0, 47, &trap47);
     1117
     1118    // additional ioapic interrupts
     1119    set_interrupt_gate(0, 48, &trap48);
     1120    set_interrupt_gate(0, 49, &trap49);
     1121    set_interrupt_gate(0, 50, &trap50);
     1122    set_interrupt_gate(0, 51, &trap51);
     1123    set_interrupt_gate(0, 52, &trap52);
     1124    set_interrupt_gate(0, 53, &trap53);
     1125    set_interrupt_gate(0, 54, &trap54);
     1126    set_interrupt_gate(0, 55, &trap55);
     1127
     1128    // configurable msi or msi-x interrupts
     1129    set_interrupt_gate(0, 56, &trap56);
     1130    set_interrupt_gate(0, 57, &trap57);
     1131    set_interrupt_gate(0, 58, &trap58);
     1132    set_interrupt_gate(0, 59, &trap59);
     1133    set_interrupt_gate(0, 60, &trap60);
     1134    set_interrupt_gate(0, 61, &trap61);
     1135    set_interrupt_gate(0, 62, &trap62);
     1136    set_interrupt_gate(0, 63, &trap63);
     1137    set_interrupt_gate(0, 64, &trap64);
     1138    set_interrupt_gate(0, 65, &trap65);
     1139    set_interrupt_gate(0, 66, &trap66);
     1140    set_interrupt_gate(0, 67, &trap67);
     1141    set_interrupt_gate(0, 68, &trap68);
     1142    set_interrupt_gate(0, 69, &trap69);
     1143    set_interrupt_gate(0, 70, &trap70);
     1144    set_interrupt_gate(0, 71, &trap71);
     1145    set_interrupt_gate(0, 72, &trap72);
     1146    set_interrupt_gate(0, 73, &trap73);
     1147    set_interrupt_gate(0, 74, &trap74);
     1148    set_interrupt_gate(0, 75, &trap75);
     1149    set_interrupt_gate(0, 76, &trap76);
     1150    set_interrupt_gate(0, 77, &trap77);
     1151    set_interrupt_gate(0, 78, &trap78);
     1152    set_interrupt_gate(0, 79, &trap79);
     1153    set_interrupt_gate(0, 80, &trap80);
     1154    set_interrupt_gate(0, 81, &trap81);
     1155    set_interrupt_gate(0, 82, &trap82);
     1156    set_interrupt_gate(0, 83, &trap83);
     1157    set_interrupt_gate(0, 84, &trap84);
     1158    set_interrupt_gate(0, 85, &trap85);
     1159    set_interrupt_gate(0, 86, &trap86);
     1160    set_interrupt_gate(0, 87, &trap87);
     1161    set_interrupt_gate(0, 88, &trap88);
     1162    set_interrupt_gate(0, 89, &trap89);
     1163    set_interrupt_gate(0, 90, &trap90);
     1164    set_interrupt_gate(0, 91, &trap91);
     1165    set_interrupt_gate(0, 92, &trap92);
     1166    set_interrupt_gate(0, 93, &trap93);
     1167    set_interrupt_gate(0, 94, &trap94);
     1168    set_interrupt_gate(0, 95, &trap95);
     1169    set_interrupt_gate(0, 96, &trap96);
     1170    set_interrupt_gate(0, 97, &trap97);
     1171
     1172    set_trap_gate(0, 98, &trap98);  // for performance testing only
     1173    set_trap_gate(0, 99, &trap99);  // syscall interrupt
     1174
     1175    // configurable msi or msi-x interrupts
     1176    set_interrupt_gate(0, 100, &trap100);
     1177    set_interrupt_gate(0, 101, &trap101);
     1178    set_interrupt_gate(0, 102, &trap102);
     1179    set_interrupt_gate(0, 103, &trap103);
     1180    set_interrupt_gate(0, 104, &trap104);
     1181    set_interrupt_gate(0, 105, &trap105);
     1182    set_interrupt_gate(0, 106, &trap106);
     1183    set_interrupt_gate(0, 107, &trap107);
     1184    set_interrupt_gate(0, 108, &trap108);
     1185    set_interrupt_gate(0, 109, &trap109);
     1186    set_interrupt_gate(0, 110, &trap110);
     1187    set_interrupt_gate(0, 111, &trap111);
     1188    set_interrupt_gate(0, 112, &trap112);
     1189    set_interrupt_gate(0, 113, &trap113);
     1190    set_interrupt_gate(0, 114, &trap114);
     1191    set_interrupt_gate(0, 115, &trap115);
     1192    set_interrupt_gate(0, 116, &trap116);
     1193    set_interrupt_gate(0, 117, &trap117);
     1194    set_interrupt_gate(0, 118, &trap118);
     1195    set_interrupt_gate(0, 119, &trap119);
     1196    set_interrupt_gate(0, 120, &trap120);
     1197    set_interrupt_gate(0, 121, &trap121);
     1198    set_interrupt_gate(0, 122, &trap122);
     1199    set_interrupt_gate(0, 123, &trap123);
     1200    set_interrupt_gate(0, 124, &trap124);
     1201    set_interrupt_gate(0, 125, &trap125);
     1202    set_interrupt_gate(0, 126, &trap126);
     1203    set_interrupt_gate(0, 127, &trap127);
     1204    set_interrupt_gate(0, 128, &trap128);
     1205    set_interrupt_gate(0, 129, &trap129);
     1206    set_interrupt_gate(0, 130, &trap130);
     1207    set_interrupt_gate(0, 131, &trap131);
     1208    set_interrupt_gate(0, 132, &trap132);
     1209    set_interrupt_gate(0, 133, &trap133);
     1210    set_interrupt_gate(0, 134, &trap134);
     1211    set_interrupt_gate(0, 135, &trap135);
     1212    set_interrupt_gate(0, 136, &trap136);
     1213    set_interrupt_gate(0, 137, &trap137);
     1214    set_interrupt_gate(0, 138, &trap138);
     1215    set_interrupt_gate(0, 139, &trap139);
     1216    set_interrupt_gate(0, 140, &trap140);
     1217    set_interrupt_gate(0, 141, &trap141);
     1218    set_interrupt_gate(0, 142, &trap142);
     1219    set_interrupt_gate(0, 143, &trap143);
     1220    set_interrupt_gate(0, 144, &trap144);
     1221    set_interrupt_gate(0, 145, &trap145);
     1222    set_interrupt_gate(0, 146, &trap146);
     1223    set_interrupt_gate(0, 147, &trap147);
     1224    set_interrupt_gate(0, 148, &trap148);
     1225    set_interrupt_gate(0, 149, &trap149);
     1226    set_interrupt_gate(0, 150, &trap150);
     1227    set_interrupt_gate(0, 151, &trap151);
     1228    set_interrupt_gate(0, 152, &trap152);
     1229    set_interrupt_gate(0, 153, &trap153);
     1230    set_interrupt_gate(0, 154, &trap154);
     1231    set_interrupt_gate(0, 155, &trap155);
     1232    set_interrupt_gate(0, 156, &trap156);
     1233    set_interrupt_gate(0, 157, &trap157);
     1234    set_interrupt_gate(0, 158, &trap158);
     1235    set_interrupt_gate(0, 159, &trap159);
     1236    set_interrupt_gate(0, 160, &trap160);
     1237    set_interrupt_gate(0, 161, &trap161);
     1238    set_interrupt_gate(0, 162, &trap162);
     1239    set_interrupt_gate(0, 163, &trap163);
     1240    set_interrupt_gate(0, 164, &trap164);
     1241    set_interrupt_gate(0, 165, &trap165);
     1242    set_interrupt_gate(0, 166, &trap166);
     1243    set_interrupt_gate(0, 167, &trap167);
     1244    set_interrupt_gate(0, 168, &trap168);
     1245    set_interrupt_gate(0, 169, &trap169);
     1246    set_interrupt_gate(0, 170, &trap170);
     1247    set_interrupt_gate(0, 171, &trap171);
     1248    set_interrupt_gate(0, 172, &trap172);
     1249    set_interrupt_gate(0, 173, &trap173);
     1250    set_interrupt_gate(0, 174, &trap174);
     1251    set_interrupt_gate(0, 175, &trap175);
     1252    set_interrupt_gate(0, 176, &trap176);
     1253    set_interrupt_gate(0, 177, &trap177);
     1254    set_interrupt_gate(0, 178, &trap178);
     1255    set_interrupt_gate(0, 179, &trap179);
     1256    set_interrupt_gate(0, 180, &trap180);
     1257    set_interrupt_gate(0, 181, &trap181);
     1258    set_interrupt_gate(0, 182, &trap182);
     1259    set_interrupt_gate(0, 183, &trap183);
     1260    set_interrupt_gate(0, 184, &trap184);
     1261    set_interrupt_gate(0, 185, &trap185);
     1262    set_interrupt_gate(0, 186, &trap186);
     1263    set_interrupt_gate(0, 187, &trap187);
     1264    set_interrupt_gate(0, 188, &trap188);
     1265    set_interrupt_gate(0, 189, &trap189);
     1266    set_interrupt_gate(0, 190, &trap190);
     1267    set_interrupt_gate(0, 191, &trap191);
     1268    set_interrupt_gate(0, 192, &trap192);
     1269    set_interrupt_gate(0, 193, &trap193);
     1270    set_interrupt_gate(0, 194, &trap194);
     1271    set_interrupt_gate(0, 195, &trap195);
     1272    set_interrupt_gate(0, 196, &trap196);
     1273    set_interrupt_gate(0, 197, &trap197);
     1274    set_interrupt_gate(0, 198, &trap198);
     1275    set_interrupt_gate(0, 199, &trap199);
     1276    set_interrupt_gate(0, 200, &trap200);
     1277    set_interrupt_gate(0, 201, &trap201);
     1278    set_interrupt_gate(0, 202, &trap202);
     1279    set_interrupt_gate(0, 203, &trap203);
     1280    set_interrupt_gate(0, 204, &trap204);
     1281    set_interrupt_gate(0, 205, &trap205);
     1282    set_interrupt_gate(0, 206, &trap206);
     1283    set_interrupt_gate(0, 207, &trap207);
     1284    set_interrupt_gate(0, 208, &trap208);
     1285    set_interrupt_gate(0, 209, &trap209);
     1286    set_interrupt_gate(0, 210, &trap210);
     1287    set_interrupt_gate(0, 211, &trap211);
     1288    set_interrupt_gate(0, 212, &trap212);
     1289    set_interrupt_gate(0, 213, &trap213);
     1290    set_interrupt_gate(0, 214, &trap214);
     1291    set_interrupt_gate(0, 215, &trap215);
     1292    set_interrupt_gate(0, 216, &trap216);
     1293    set_interrupt_gate(0, 217, &trap217);
     1294    set_interrupt_gate(0, 218, &trap218);
     1295    set_interrupt_gate(0, 219, &trap219);
     1296    set_interrupt_gate(0, 220, &trap220);
     1297    set_interrupt_gate(0, 221, &trap221);
     1298    set_interrupt_gate(0, 222, &trap222);
     1299    set_interrupt_gate(0, 223, &trap223);
     1300    set_interrupt_gate(0, 224, &trap224);
     1301    set_interrupt_gate(0, 225, &trap225);
     1302    set_interrupt_gate(0, 226, &trap226);
     1303    set_interrupt_gate(0, 227, &trap227);
     1304    set_interrupt_gate(0, 228, &trap228);
     1305    set_interrupt_gate(0, 229, &trap229);
     1306    set_interrupt_gate(0, 230, &trap230);
     1307    set_interrupt_gate(0, 231, &trap231);
     1308    set_interrupt_gate(0, 232, &trap232);
     1309    set_interrupt_gate(0, 233, &trap233);
     1310    set_interrupt_gate(0, 234, &trap234);
     1311    set_interrupt_gate(0, 235, &trap235);
     1312    set_interrupt_gate(0, 236, &trap236);
     1313    set_interrupt_gate(0, 237, &trap237);
     1314    set_interrupt_gate(0, 238, &trap238);
     1315    set_interrupt_gate(0, 239, &trap239);
     1316    set_interrupt_gate(0, 240, &trap240);
     1317    set_interrupt_gate(0, 241, &trap241);
     1318    set_interrupt_gate(0, 242, &trap242);
     1319    set_interrupt_gate(0, 243, &trap243);
     1320    set_interrupt_gate(0, 244, &trap244);
     1321    set_interrupt_gate(0, 245, &trap245);
     1322    set_interrupt_gate(0, 246, &trap246);
     1323    set_interrupt_gate(0, 247, &trap247);
     1324    set_interrupt_gate(0, 248, &trap248);
     1325    set_interrupt_gate(0, 249, &trap249);
     1326    set_interrupt_gate(0, 250, &trap250);
     1327
     1328    // smp / apic local interrupts
     1329    set_interrupt_gate(0, 251, &trap251);
     1330    set_interrupt_gate(0, 252, &trap252);
     1331    set_interrupt_gate(0, 253, &trap253);
     1332    set_interrupt_gate(0, 254, &trap254);
     1333    set_interrupt_gate(0, 255, &trap255);
     1334
     1335    // init interrupt handler table
     1336    table = gInterruptHandlerTable;
     1337
     1338    // defaults
     1339    for (i = 0; i < ARCH_INTERRUPT_BASE; i++)
     1340        table[i] = invalid_exception;
     1341    for (i = ARCH_INTERRUPT_BASE; i < INTERRUPT_HANDLER_TABLE_SIZE; i++)
     1342        table[i] = hardware_interrupt;
     1343
     1344    table[0] = unexpected_exception;    // Divide Error Exception (#DE)
     1345    table[1] = x86_64_handle_debug_exception; // Debug Exception (#DB)
     1346    table[2] = fatal_exception;         // NMI Interrupt
     1347    table[3] = x86_64_handle_breakpoint_exception; // Breakpoint Exception (#BP)
     1348    table[4] = unexpected_exception;    // Overflow Exception (#OF)
     1349    table[5] = unexpected_exception;    // BOUND Range Exceeded Exception (#BR)
     1350    table[6] = unexpected_exception;    // Invalid Opcode Exception (#UD)
     1351    table[7] = fatal_exception;         // Device Not Available Exception (#NM)
     1352    table[8] = x86_64_double_fault_exception; // Double Fault Exception (#DF)
     1353    table[9] = fatal_exception;         // Coprocessor Segment Overrun
     1354    table[10] = fatal_exception;        // Invalid TSS Exception (#TS)
     1355    table[11] = fatal_exception;        // Segment Not Present (#NP)
     1356    table[12] = fatal_exception;        // Stack Fault Exception (#SS)
     1357    table[13] = unexpected_exception;   // General Protection Exception (#GP)
     1358    table[14] = page_fault_exception;   // Page-Fault Exception (#PF)
     1359    table[16] = unexpected_exception;   // x87 FPU Floating-Point Error (#MF)
     1360    table[17] = unexpected_exception;   // Alignment Check Exception (#AC)
     1361    table[18] = fatal_exception;        // Machine-Check Exception (#MC)
     1362    table[19] = unexpected_exception;   // SIMD Floating-Point Exception (#XF)
     1363
     1364    return B_OK;
     1365}
     1366
     1367
     1368status_t
     1369arch_int_init_post_vm(struct kernel_args *args)
     1370{
     1371    // Always init the local apic as it can be used for timers even if we
     1372    // don't end up using the io apic
     1373    apic_init(args);
     1374
     1375    // We need to map in the I/O APIC here, since we would lose the already
     1376    // wired mapping before arch_int_init_io() is called.
     1377    ioapic_map(args);
     1378
     1379    // create IDT area for the boot CPU
     1380    area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
     1381        B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
     1382    if (area < 0)
     1383        return area;
     1384
     1385    // create IDTs for the off-boot CPU
     1386    size_t idtSize = 256 * 8;
     1387        // 256 8 bytes-sized descriptors
     1388    int32 cpuCount = smp_get_num_cpus();
     1389    if (cpuCount > 0) {
     1390        size_t areaSize = ROUNDUP(cpuCount * idtSize, B_PAGE_SIZE);
     1391        desc_table* idt;
     1392        virtual_address_restrictions virtualRestrictions = {};
     1393        virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
     1394        physical_address_restrictions physicalRestrictions = {};
     1395        area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS,
     1396            B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
     1397            &virtualRestrictions, &physicalRestrictions, (void**)&idt);
     1398        if (area < 0)
     1399            return area;
     1400
     1401        for (int32 i = 1; i < cpuCount; i++) {
     1402            sIDTs[i] = idt;
     1403            memcpy(idt, sIDTs[0], idtSize);
     1404            idt += 256;
     1405            // The CPU's IDTR will be set in arch_cpu_init_percpu().
     1406        }
     1407    }
     1408
     1409    return area >= B_OK ? B_OK : area;
     1410}
     1411
     1412
     1413status_t
     1414arch_int_init_io(kernel_args* args)
     1415{
     1416    ioapic_init(args);
     1417    return B_OK;
     1418}
     1419
     1420
     1421status_t
     1422arch_int_init_post_device_manager(struct kernel_args *args)
     1423{
     1424    return B_OK;
     1425}
     1426
  • src/system/kernel/arch/x86_64/arch_vm_translation_map.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com.
     3 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
     4 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     5 * Distributed under the terms of the MIT License.
     6 *
     7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
     8 * Distributed under the terms of the NewOS License.
     9 */
     10
     11
     12#include <KernelExport.h>
     13#include <boot/kernel_args.h>
     14#include <arch/vm_translation_map.h>
     15
     16#include "paging/X86_64PagingMethod.h"
     17
     18
     19//#define TRACE_VM_TMAP
     20#ifdef TRACE_VM_TMAP
     21#   define TRACE(x...) dprintf(x)
     22#else
     23#   define TRACE(x...) ;
     24#endif
     25
     26
     27X86_64PagingMethod* gX86_64PagingMethod;
     28
     29
     30status_t
     31arch_vm_translation_map_init(kernel_args *args,
     32        VMPhysicalPageMapper** _physicalPageMapper)
     33{
     34    TRACE("vm_translation_map_init: entry\n");
     35
     36#ifdef TRACE_VM_TMAP
     37    TRACE("physical memory ranges:\n");
     38    for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
     39        phys_addr_t start = args->physical_memory_range[i].start;
     40        phys_addr_t end = start + args->physical_memory_range[i].size;
     41        TRACE("  %#10" B_PRIxPHYSADDR " - %#10" B_PRIxPHYSADDR "\n", start,
     42            end);
     43    }
     44
     45    TRACE("allocated physical ranges:\n");
     46    for (uint32 i = 0; i < args->num_physical_allocated_ranges; i++) {
     47        phys_addr_t start = args->physical_allocated_range[i].start;
     48        phys_addr_t end = start + args->physical_allocated_range[i].size;
     49        TRACE("  %#10" B_PRIxPHYSADDR " - %#10" B_PRIxPHYSADDR "\n", start,
     50            end);
     51    }
     52
     53    TRACE("allocated virtual ranges:\n");
     54    for (uint32 i = 0; i < args->num_virtual_allocated_ranges; i++) {
     55        addr_t start = args->virtual_allocated_range[i].start;
     56        addr_t end = start + args->virtual_allocated_range[i].size;
     57        TRACE("  %#10" B_PRIxADDR " - %#10" B_PRIxADDR "\n", start, end);
     58    }
     59#endif
     60
     61    gX86_64PagingMethod = new X86_64PagingMethod;
     62
     63    return gX86_64PagingMethod->Init(args, _physicalPageMapper);
     64}
     65
     66status_t
     67arch_vm_translation_map_create_map(bool kernel, VMTranslationMap** _map)
     68{
     69    return gX86_64PagingMethod->CreateTranslationMap(kernel, _map);
     70}
     71
     72
     73status_t
     74arch_vm_translation_map_init_post_area(kernel_args *args)
     75{
     76    TRACE("vm_translation_map_init_post_area: entry\n");
     77
     78    return gX86_64PagingMethod->InitPostArea(args);
     79}
     80
     81
     82status_t
     83arch_vm_translation_map_init_post_sem(kernel_args *args)
     84{
     85    return B_OK;
     86}
     87
     88status_t
     89arch_vm_translation_map_early_map(kernel_args *args, addr_t va, phys_addr_t pa,
     90    uint8 attributes, phys_addr_t (*get_free_page)(kernel_args *))
     91{
     92    TRACE("early_tmap: entry pa 0x%llx va 0x%llx\n", pa, va);
     93
     94    return gX86_64PagingMethod->MapEarly(args, va, pa, attributes, get_free_page);
     95}
     96
     97bool
     98arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress,
     99        uint32 protection)
     100{
     101    return gX86_64PagingMethod->IsKernelPageAccessible(virtualAddress, protection);
     102}
     103
  • src/system/kernel/arch/x86_64/arch_system_info.cpp

     
     1/*
     2 * Copyright 2010, Nathan Mentley, nathanmentley@gmail.com. All Rights Reserved.
     3 * Distributed under the terms of the MIT license.
     4 *
     5 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
     6 * Distributed under the terms of the MIT License.
     7 */
     8
     9
     10#include <arch/system_info.h>
     11
     12#include <string.h>
     13
     14#include <KernelExport.h>
     15#include <OS.h>
     16
     17#include <boot/kernel_args.h>
     18#include <cpu.h>
     19#include <kernel.h>
     20#include <smp.h>
     21
     22
     23uint32 sCpuType;
     24int32 sCpuRevision;
     25int64 sCpuClockSpeed;
     26
     27
     28static bool
     29get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint64 raxRegister,
     30    uint32 forCPU)
     31{
     32    if (currentCPU != forCPU)
     33        return false;
     34
     35    get_current_cpuid(info, raxRegister);
     36    return true;
     37}
     38
     39
     40status_t
     41get_cpuid(cpuid_info *info, uint64 raxRegister, uint32 forCPU)
     42{
     43    uint32 numCPUs = (uint32)smp_get_num_cpus();
     44    cpu_status state;
     45
     46    if (forCPU >= numCPUs)
     47        return B_BAD_VALUE;
     48
     49    // prevent us from being rescheduled
     50    state = disable_interrupts();
     51
     52    // ToDo: as long as we only run on pentium-class systems, we can assume
     53    //  that the CPU supports cpuid.
     54
     55    if (!get_cpuid_for(info, smp_get_current_cpu(), raxRegister, forCPU)) {
     56        smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (addr_t)info,
     57            raxRegister, forCPU, (void *)get_cpuid_for, SMP_MSG_FLAG_SYNC);
     58    }
     59
     60    restore_interrupts(state);
     61    return B_OK;
     62}
     63
     64
     65status_t
     66arch_get_system_info(system_info *info, size_t size)
     67{
     68    info->cpu_type = (cpu_types)sCpuType;
     69    info->cpu_revision = sCpuRevision;
     70
     71    // - various cpu_info
     72    info->cpu_clock_speed = sCpuClockSpeed;
     73    // - bus_clock_speed
     74    info->platform_type = B_AT_CLONE_PLATFORM;
     75
     76    // ToDo: clock speeds could be retrieved via SMBIOS/DMI
     77    return B_OK;
     78}
     79
     80
     81status_t
     82arch_system_info_init(struct kernel_args *args)
     83{
     84    // This is what you get if the CPU vendor is not recognized
     85    // or the CPU does not support cpuid with eax == 1.
     86    uint32 base;
     87    uint32 model = 0;
     88    cpu_ent *cpu = get_cpu_struct();
     89
     90    switch (cpu->arch.vendor) {
     91        case VENDOR_INTEL:
     92            base = B_CPU_INTEL_x86;
     93            break;
     94        case VENDOR_AMD:
     95            base = B_CPU_AMD_x86;
     96            break;
     97        case VENDOR_CYRIX:
     98            base = B_CPU_CYRIX_x86;
     99            break;
     100        case VENDOR_UMC:
     101            base = B_CPU_INTEL_x86; // XXX
     102            break;
     103        case VENDOR_NEXGEN:
     104            base = B_CPU_INTEL_x86; // XXX
     105            break;
     106        case VENDOR_CENTAUR:
     107            base = B_CPU_VIA_IDT_x86;
     108            break;
     109        case VENDOR_RISE:
     110            base = B_CPU_RISE_x86;
     111            break;
     112        case VENDOR_TRANSMETA:
     113            base = B_CPU_TRANSMETA_x86;
     114            break;
     115        case VENDOR_NSC:
     116            base = B_CPU_NATIONAL_x86;
     117            break;
     118        default:
     119            base = B_CPU_x86;
     120    }
     121
     122    if (base != B_CPU_x86) {
     123        if (base == B_CPU_INTEL_x86) {
     124            model = (cpu->arch.extended_family << 20)
     125                + (cpu->arch.extended_model << 16)
     126                + (cpu->arch.family << 4) + cpu->arch.model;
     127        } else {
     128            model = (cpu->arch.family << 4) +
     129            cpu->arch.model;
     130            // There isn't much useful information yet in the extended
     131            // family and extended model fields of AMD processors
     132            // and is probably undefined for others
     133        }
     134    }
     135
     136    sCpuRevision = (cpu->arch.extended_family << 18)
     137        | (cpu->arch.extended_model << 14) | (cpu->arch.type << 12)
     138        | (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping;
     139
     140    sCpuType = base + model;
     141    sCpuClockSpeed = args->arch_args.cpu_clock_speed;
     142    return B_OK;
     143}
     144
     145status_t
     146_user_get_cpuid(cpuid_info *userInfo, uint64 raxRegister, uint32 cpuNum)
     147{
     148    cpuid_info info;
     149    status_t status;
     150
     151    if (!IS_USER_ADDRESS(userInfo))
     152        return B_BAD_ADDRESS;
     153
     154    status = get_cpuid(&info, raxRegister, cpuNum);
     155
     156    if (status == B_OK
     157        && user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK)
     158        return B_BAD_ADDRESS;
     159
     160    return status;
     161}